WPF:如何在ViewModel中调用自定义UserControl的函数

4

我有一个使用WPF定义的自定义控件,它位于一个独立的程序集中。在另一个项目中,我只需要引用它,并像这样在XAML中使用:

<my:CustomUserControl Name="myControl" IsEnabled="{Binding CanTheUserInputTrade}"/>

CustomUserControl类有一个名为“Reset”的成员函数。

我曾经在View.xaml.cs文件中使用以下代码调用此函数:

myControl.Reset()

然而,由于某种合理的原因,我必须把调用此函数的逻辑移到ViewModel中。据我所知,在ViewModel中引用视图并不是一个好习惯。因此,我将无法从ViewModel中访问“myControl”引用。
我的问题是:如何在ViewModel中调用Reset函数?
这是一个常见的用例,我相信有办法做到这一点。能否有人指引我正确的方向。
非常感谢。

你什么时候需要调用这个重置方法? - pdiddy
如果您想提供更多信息,请编辑您的问题。如果您的问题范围已超出此范围,只需提出一个新问题即可。 - Tim Post
2个回答

5
过去我曾经在View的代码后台中挂接事件。
视图模型:
public ICommand ResetCommand {get; set;}

从UserControl的OnLoad方法开始:

private void MyUserControl_Loaded(object sender, RoutedEventArgs e)
{
    MyUserControl ctrl = sender as MyUserControl;
    if (ctrl == null) return;

    MyViewModel vm = ctrl.DataContext as MyViewModel ;

    if (vm == null)
        return;

    vm.ResetCommand = new RelayCommand(param => this.Reset());
}

嗨,Rachel,这是解决问题的好主意。然而,UserControl被编写为代码的常见部分,用于许多地方。将硬编码的DataContect -> MyViewModel转换放置在一起会使它们紧密耦合。有没有什么方法可以摆脱紧密耦合? - Kevin
如果您的UI与其他ViewModel一起使用,则意味着某些东西在某个时候将它们链接在一起。无论是什么,都应该负责将ViewModel.ResetCommand连接到View.Reset()。 - Rachel
你可以使用接口使其更具可重用性。我将在下面发布一个完整的示例... - Dan Field

2

@Rachel的解决方案很棒。使用接口可以使其更加松耦合:

using System.Windows.Input;

namespace WpfApplication
{
    public interface IResetCaller
    {
        ICommand ResetCommand { get; set; }
    }
}

让你的基本视图模型实现这个接口,例如:
public class MyViewModel : ModelBase, IResetCaller
{
    ...
    public ICommand RefreshSegmentCommand { get; set; }
}

而Rachel的代码变成了:

private void MyUserControl_Loaded(object sender, RoutedEventArgs e)
{
    var ctrl = sender as FrameworkElement;
    if (ctrl == null) return;

    var vm = ctrl.DataContext as IResetCaller;

    if (vm == null)
        return;

    vm.ResetCommand = new RelayCommand(param => this.Reset(param));
}

这个接口可以用于装饰任意数量的视图模型,而且接口可以在与UserControl相同的库中定义。在主ViewModel中,你只需要像这样做:ResetCommand.Execute(this)或者传递任何你想要的参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接