MVVM:将控制权带入视图

时间:2014-06-02 19:57:19

标签: c# wpf mvvm scrollview

我周围有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。

有更好的方法吗?

1 个答案:

答案 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方法的方法的资源,但是如果你也选择使用它,那么太棒了!