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:将控制带入视图

当我第一次看到你的问题时,我认为用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方法,但如果你也选择使用它,那就太好了!