MVVM:将控制带入视图
本文关键字:视图 控制 MVVM | 更新日期: 2023-09-27 18:06:12
我有一个Grid
周围的ScrollViewer
。在ScrollViewer
的顶端是Button
。点击Button
,我希望ScrollViewer
滚动到ScrollViewer
底部的Control
。
使用下面的XAML,我可以将控件带入视图:
<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。
有更好的方法吗?
当我第一次看到你的问题时,我认为用MVVM处理事件的一般解决方案是在附加属性中处理它们。然而,再看一遍,我突然想到你的不是实际上处理任何事件…你只是想从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();
}
}
现在我们可以在视图代码后面的Loaded
事件处理程序中将这个方法设置为delegate
的一个(或多个)处理程序:
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
声明和处理方法中添加或删除它们…简单。
这是一个MVVM方法从视图模型调用UI控件上的方法。但是,在您的情况下,很可能会认为实现此方法是多余的,因为您可以将BringIntoView
代码放入附加到Button
的基本Click
处理程序中。我提供这个答案更多的是作为一种资源,供将来的用户寻找一种方法来从视图模型中实际调用UI方法,但如果你也选择使用它,那就太好了!