一般来说,实现这一目标的最佳方法是使用行为。实现可能取决于您的具体要求,但我将在此处提供一个通用示例,展示如何使视图模型触发 ListBox 滚动到您选择的特定项目。
首先,您需要一种将其从视图模型传递到视图的方法,您不能直接绑定到 XAML 中的事件,但您可以将事件封装在包装器中并绑定到它:
public class ListBoxScrollHandler
{
public event Action<object> ScrollEvent;
public void ScrollTo(object item)
{
if (this.ScrollEvent != null)
this.ScrollEvent(item);
}
}
该类包含我们的行为可以绑定到的事件和我们的视图模型可以调用的ScrollTo 方法。对于视图,让我们创建一个简单的列表框,我们将用数字(实际上是字符串)和一个按钮来填充它,该按钮将迫使我们滚动到内容为“500”的元素:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Button Content="Scroll to 500" HorizontalAlignment="Left" VerticalAlignment="Top" Command="{Binding ScrollCommand}" CommandParameter="500" />
<ListBox Grid.Row="1" ItemsSource="{Binding MyItems}" SelectedItem="{Binding CurrentItem}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<i:Interaction.Behaviors>
<behaviors:ListBoxScrollBehavior ScrollHandler="{Binding ScrollHandler}" />
</i:Interaction.Behaviors>
</ListBox>
</Grid>
如您所见,我已经使用 Blend 行为实现了这一点,如果您愿意,当然可以使用常规附加行为来实现它,但我在这里保持简单:
public class ListBoxScrollBehavior : Behavior<ListBox>
{
public ListBoxScrollHandler ScrollHandler
{
get { return (ListBoxScrollHandler)GetValue(ScrollHandlerProperty); }
set { SetValue(ScrollHandlerProperty, value); }
}
public static readonly DependencyProperty ScrollHandlerProperty =
DependencyProperty.Register("ScrollHandler", typeof(ListBoxScrollHandler),
typeof(ListBoxScrollBehavior), new PropertyMetadata(null, OnScrollHandlerChanged));
protected override void OnAttached()
{
base.OnAttached();
}
protected override void OnDetaching()
{
base.OnDetaching();
}
private static void OnScrollHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = d as ListBoxScrollBehavior;
if (behavior == null)
return;
var oldHandler = e.OldValue as ListBoxScrollHandler;
if (oldHandler != null)
oldHandler.ScrollEvent -= behavior.ScrollTo;
var newHandler = e.NewValue as ListBoxScrollHandler;
if (newHandler != null)
newHandler.ScrollEvent += behavior.ScrollTo;
}
public void ScrollTo(object item)
{
this.AssociatedObject.ScrollIntoView(item);
}
}
所以我们的行为包含一个“ScrollHandler”依赖属性,我们可以绑定到我们的视图模型并通过调用列表框的 ScrollIntoView 方法来响应。之后,只需创建一个提供此属性的视图模型以及用于初始化列表项的代码和一个响应按钮按下并调用它的滚动处理程序的 ScrollTo 方法的命令处理程序:
public class MainViewModel : ViewModelBase
{
private ObservableCollection<string> _MyItems = new ObservableCollection<string>();
public ObservableCollection<string> MyItems
{
get { return this._MyItems; }
set { this._MyItems = value; RaisePropertyChanged(); }
}
private string _SelectedItem;
public string SelectedItem
{
get { return this._SelectedItem; }
set { this._SelectedItem = value; RaisePropertyChanged(); }
}
public ICommand ScrollCommand { get { return new RelayCommand<string>(OnScroll); } }
private void OnScroll(string item)
{
this.ScrollHandler.ScrollTo(item);
}
private ListBoxScrollHandler _ScrollHandler = new ListBoxScrollHandler();
public ListBoxScrollHandler ScrollHandler
{
get { return this._ScrollHandler;}
set { this._ScrollHandler = value; RaisePropertyChanged(); }
}
public MainViewModel()
{
for (int i = 0; i < 1000; i++)
this.MyItems.Add(i.ToString());
}
}
运行代码,单击按钮,列表框将向下滚动到包含“500”内容的元素。显然,如果您只需要此行为的一个子集(例如,滚动到当前选定的项目),那么您可以相应地修改此行为。