我周围有Grid
ScrollViewer
。我ScrollViewer
的顶部是Button
。点击Button
,我希望ScrollViewer
滚动到Control
底部的ScrollViewer
。
使用以下XAML,我可以将Control带入视图:
<Button Grid.Row="2" Content="Some Button" Command="{Binding DoJumpCommand}" CommandParameter="{Binding ElementName=window}"/>
ViewModel中的命令是:
if (parameter is MainWindowView)
{
var mainWindowView = parameter as MainWindowView;
mainWindowView.myJumpTarget.BringIntoView();
}
这很好用。但我不确定这是否是干净的MVVM,因为我将完整的视图传递给ViewModel。
有更好的方法吗?
答案 0 :(得分:1)
当我第一次看到你的问题时,我认为使用MVVM处理事件的一般解决方案是在Attached Property中处理它们。但是,再看一遍,我发现你不实际处理任何事件......你只想从UI控件中调用一个方法。实际上,您只需要将视图模型中的消息传递给视图。有很多方法可以做到这一点,但我最喜欢的方法是定义自定义delegate
。
首先,让我们在视图模型中创建实际的delegate
:
public delegate void TypeOfDelegate();
它不需要任何输入参数,因为除了信号之外你不需要将任何东西从视图模型传递到视图......你打算滚动ScrollViewer
。
现在让我们添加一个getter和setter:
public TypeOfDelegate DelegateProperty { get; set; }
现在让我们在后面的代码中创建一个匹配delegate
的in和out参数的方法(在你的情况下没有):
public void CanBeCalledAnythingButMustMatchTheDelegateSignature()
{
if (window is MainWindowView) // Set whatever conditions you want here
{
window.myJumpTarget.BringIntoView();
}
}
现在我们可以在后面的视图代码中的delegate
事件处理程序中将此方法设置为此Loaded
中的一个(多个)处理程序:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Assumes your DataContext is correctly set to an instance of YourViewModel
YourViewModel viewModel = (YourViewModel)DataContext;
viewModel.DelegateProperty += CanBeCalledAnythingButMustMatchTheDelegateSignature;
}
最后,让我们从视图模型中调用我们的delegate
...这相当于提升事件:
if (DelegateProperty != null) DelegateProperty(dataInstanceOfTypeYourDataType);
请注意null
的重要检查。如果DelegateProperty
不是null
,则将逐个调用所有附加的处理程序方法。就是这样了!如果您想要更多或更少的参数,只需在delegate
声明和处理方法中添加或删除它们......简单。
因此,这是一种从视图模型调用UI控件上的方法的MVVM方法。但是,在您的情况下,很可能会认为实施此方法会过度,因为您可以将BringIntoView
代码放入附加到Click
的基本Button
处理程序中。我已经提供了这个答案作为未来用户寻找从视图模型实际调用UI方法的方法的资源,但是如果你也选择使用它,那么太棒了!