我有一个带有列表框的XAML视图:
<control:ListBoxScroll ItemSource="{Binding Path=FooCollection}"
SelectedItem="{Binding SelectedFoo, Mode=TwoWay}"
ScrollSelectedItem="{Binding SelectedFoo}">
<!-- data templates, etc. -->
</control:ListBoxScroll>
Run Code Online (Sandbox Code Playgroud)
所选项目绑定到我视图中的属性.当用户选择列表框中的项目时,视图模型中的SelectedFoo属性会更新.当我在视图模型中设置SelectedFoo属性时,在列表框中选择了正确的项目.
问题是,如果代码中设置的SelectedFoo当前不可见,我需要另外调用ScrollIntoView列表框.由于我的ListBox在视图中,而我的逻辑在我的视图模型中...我找不到方便的方法来做到这一点.所以我扩展了ListBoxScroll:
class ListBoxScroll : ListBox
{
public static readonly DependencyProperty ScrollSelectedItemProperty = DependencyProperty.Register(
"ScrollSelectedItem",
typeof(object),
typeof(ListBoxScroll),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(onScrollSelectedChanged)));
public object ScrollSelectedItem
{
get { return (object)GetValue(ScrollSelectedItemProperty); }
set { SetValue(ScrollSelectedItemProperty, value); }
}
private static void onScrollSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listbox = d as ListBoxScroll;
listbox.ScrollIntoView(e.NewValue);
}
}
Run Code Online (Sandbox Code Playgroud)
它基本上公开了一个新的依赖属性ScrollSelectedItem,它绑定到SelectedFoo我的视图模型上的属性.然后我挂钩属性更改依赖属性的回调并将新选择的项目滚动到视图中.
有没有其他人知道在视图模型支持的XAML视图上调用用户控件上的函数的更简单方法?这有点像:
将逻辑放在ScrollSelectedItem { set {方法中会很好,但依赖框架似乎潜行并设法工作而不实际调用它.
Ank*_*esh 51
您是否尝试过使用行为...这是一个ScrollInViewBehavior.我已经将它用于ListView和DataGrid .....我认为它应该适用于ListBox ......
您必须添加System.Windows.Interactivity要使用的引用 Behavior<T> class
public class ScrollIntoViewForListBox : Behavior<ListBox>
{
/// <summary>
/// When Beahvior is attached
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
}
/// <summary>
/// On Selection Changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void AssociatedObject_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
if (sender is ListBox)
{
ListBox listBox = (sender as ListBox);
if (listBox .SelectedItem != null)
{
listBox.Dispatcher.BeginInvoke(
(Action) (() =>
{
listBox.UpdateLayout();
if (listBox.SelectedItem !=
null)
listBox.ScrollIntoView(
listBox.SelectedItem);
}));
}
}
}
/// <summary>
/// When behavior is detached
/// </summary>
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.SelectionChanged -=
AssociatedObject_SelectionChanged;
}
}
Run Code Online (Sandbox Code Playgroud)
将别名添加到XAMLas xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
然后在你的 Control
<ListBox ItemsSource="{Binding Path=MyList}"
SelectedItem="{Binding Path=MyItem,
Mode=TwoWay}"
SelectionMode="Single">
<i:Interaction.Behaviors>
<Behaviors:ScrollIntoViewForListBox />
</i:Interaction.Behaviors>
</ListBox>
Run Code Online (Sandbox Code Playgroud)
现在,当ViewModel重新选择更改时,将在列表中设置"MyItem"属性时滚动.
Jam*_*ett 34
在查看答案后,出现了一个共同的主题:外部类侦听ListBox的SelectionChanged事件.这让我意识到依赖属性方法是过度的,我可以让子类自己听:
class ListBoxScroll : ListBox
{
public ListBoxScroll() : base()
{
SelectionChanged += new SelectionChangedEventHandler(ListBoxScroll_SelectionChanged);
}
void ListBoxScroll_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ScrollIntoView(SelectedItem);
}
}
Run Code Online (Sandbox Code Playgroud)
我觉得这是做我想要的最简单的解决方案.
值得一提的是adcool2007用于提升行为.以下是一些感兴趣的文章:
http://blogs.msdn.com/b/johngossman/archive/2008/05/07/the-attached-behavior-pattern.aspx
http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx
我认为对于将被添加到几个不同用户控件的通用行为(例如,点击行为,拖动行为,动画行为等),然后附加的行为很有意义.我不想在这种特殊情况下使用它们的原因是行为(调用ScrollIntoView)的实现不是可以发生在除ListBox之外的任何控件上的通用操作.
sel*_*dog 17
因为这严格来说是一个View问题,所以没有理由为此目的在视图后面的代码中没有事件处理程序.收听ListBox.SelectionChanged并使用它将新选择的项目滚动到视图中.
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
((ListBox)sender).ScrollIntoView(e.AddedItems[0]);
}
Run Code Online (Sandbox Code Playgroud)
你也不需要派生ListBox来做这件事.只需使用标准控件,当ListBox.SelectedItem值发生变化时(如原始问题中所述),将执行上述处理程序并将项目滚动到视图中.
<ListBox
ItemsSource="{Binding Path=FooCollection}"
SelectedItem="{Binding Path=SelectedFoo}"
SelectionChanged="ListBox_SelectionChanged"
/>
Run Code Online (Sandbox Code Playgroud)
另一种方法是编写一个附加属性,该属性侦听ICollectionView.CurrentChanged然后调用ListBox.ScrollIntoView新的当前项.如果您需要多个列表框的此功能,这是一种更"可重用"的方法.你可以在这里找到一个很好的例子来帮助你入门:http://michlg.wordpress.com/2010/01/16/listbox-automatically-scroll-currentitem-into-view/
Dut*_*tts 11
我知道这是一个古老的问题,但是我最近对同样问题的搜索引起了我的注意.我想使用行为方法,但不希望依赖于Blend SDK只是为了给我Behavior<T>这样的解决方案而不是它:
public static class ListBoxBehavior
{
public static bool GetScrollSelectedIntoView(ListBox listBox)
{
return (bool)listBox.GetValue(ScrollSelectedIntoViewProperty);
}
public static void SetScrollSelectedIntoView(ListBox listBox, bool value)
{
listBox.SetValue(ScrollSelectedIntoViewProperty, value);
}
public static readonly DependencyProperty ScrollSelectedIntoViewProperty =
DependencyProperty.RegisterAttached("ScrollSelectedIntoView", typeof (bool), typeof (ListBoxBehavior),
new UIPropertyMetadata(false, OnScrollSelectedIntoViewChanged));
private static void OnScrollSelectedIntoViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var selector = d as Selector;
if (selector == null) return;
if (e.NewValue is bool == false)
return;
if ((bool) e.NewValue)
{
selector.AddHandler(Selector.SelectionChangedEvent, new RoutedEventHandler(ListBoxSelectionChangedHandler));
}
else
{
selector.RemoveHandler(Selector.SelectionChangedEvent, new RoutedEventHandler(ListBoxSelectionChangedHandler));
}
}
private static void ListBoxSelectionChangedHandler(object sender, RoutedEventArgs e)
{
if (!(sender is ListBox)) return;
var listBox = (sender as ListBox);
if (listBox.SelectedItem != null)
{
listBox.Dispatcher.BeginInvoke(
(Action)(() =>
{
listBox.UpdateLayout();
if (listBox.SelectedItem !=null)
listBox.ScrollIntoView(listBox.SelectedItem);
}));
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用就是
<ListBox ItemsSource="{Binding Path=MyList}"
SelectedItem="{Binding Path=MyItem, Mode=TwoWay}"
SelectionMode="Single"
behaviors:ListBoxBehavior.ScrollSelectedIntoView="True">
Run Code Online (Sandbox Code Playgroud)
小智 7
试试这个:
private void lstBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
lstBox.ScrollIntoView(lstBox.SelectedItem);
}
Run Code Online (Sandbox Code Playgroud)
我正在使用这个(在我看来)明确而简单的解决方案
listView.SelectionChanged += (s, e) =>
listView.ScrollIntoView(listView.SelectedItem);
Run Code Online (Sandbox Code Playgroud)
其中xaml中listView的ListView控件名称SelectedItem受我的MVVM影响,代码插入 xaml.cs文件中的构造函数中.