【问题标题】:Communication between ViewModel and UserControl's viewViewModel 和 UserControl 的视图之间的通信
【发布时间】:2016-02-16 18:11:41
【问题描述】:

我从事 WPF MVVM 项目。我在 MainWindow 的视图模型和 usercontrol 的视图之间进行通信,放在 MainWindow 内。

所以我有:

  • 用户控件

  • 主窗口

  • MainWindowViewModel

我的UserControl很简单:

<Grid MouseDown="UIElement_OnMouseDown">
    <Rectangle Fill="BlueViolet" />
</Grid>

带有代码隐藏(在单击矩形时触发一个事件,并传递坐标):

public partial class FooUserControl : UserControl
{
    public FooUserControl()
    {
        InitializeComponent();
    }

    public event EventHandler<BarEventArgs> BarClick;
    private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        double x = e.GetPosition(this).X;
        double y = e.GetPosition(this).Y;
        string value_to_pass = "[" + x + "," + y + "]";

        BarEventArgs bar = new BarEventArgs() { Bar = 2, Foo = value_to_pass };
        BarClick?.Invoke(sender, bar);
    }
}

我的 MainWindow 没有代码隐藏。只是xml。如您所见,我通过命令将点击事件传递给 MainWindowViewModel

<Window.DataContext>
    <viewModels:MainWindowViewModel />
</Window.DataContext>
<Grid>
    <local:FooUserControl>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="BarClick">
                <cmd:EventToCommand Command="{Binding ClickedCommand}" PassEventArgsToCommand="True" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </local:FooUserControl>
</Grid>

最后我的 MainWindowViewModel 有这个命令:

public class MainWindowViewModel : ObservableObject
{
    public ICommand ClickedCommand => new RelayCommand<BarEventArgs>(o => Clicked(o.Foo));
    private void Clicked(string a)
    {
        Debug.WriteLine("Clicked " + a);
    }
}

因此,通过命令从 UserControl 的视图到 MainWindow 的视图模型的通信效果很好。但是,我该如何以相反的方式进行交流?从 MainWindowViewModel 到 UserControl 的视图?

【问题讨论】:

  • 您想进行什么样的交流...?您可以寻找双向绑定。
  • 在 UserControl 的表面上公开一个 ICommand。在您的 ViewModel 中绑定到它。现在 UserControl 可以直接与您的视图模型通信。沙赞。通讯回来了?在 UserControl 上公开它需要的任何属性。也许是一个点?或者也许是鞋子?我不知道。现在,视图模型将它们的属性设置为所需颜色的鞋子,并且通过更改通知,UserControl 可以自行更新。您拥有 MVVM 批准的双向通信。布拉姆。
  • 您的FooUserControl 是否应该可以跨应用程序重用(=UserControl)或特定于您的应用程序(=View)。 UserControls 没有 ViewModel(只提供绑定到一个的依赖属性),只有 Views 有特定的 viewmodels (UserView => UserViewModel)。
  • @Tseng 这就是我所拥有的。当我说“ViewModel”时,我指的是放置 FooUserControl 的视图的视图模型。
  • 这就是 INotifiyPropertyChangedINotifyCollectionChanged 接口的用途,当值发生变化时告诉视图,你显然应该知道这一点,因为你实现了一个 ObservableObject 这听起来像一个类型实现INotifyPropertyChanged (INPC)

标签: c# .net wpf xaml mvvm


【解决方案1】:

您的 ViewModel 不应直接访问您的 View。他们根本不应该关心视图。他们所做的只是提供属性以使数据可用。视图现在可以绑定到这些属性。

因此,从 ViewModel 到 View 的所有通信都只能通过 Bindings 进行。当 ViewModel 必须告诉 View 一些事情时,它提供了一个属性。然后由 View 绑定到该属性并使用它做一些事情——不管这可能是什么。

【讨论】:

  • 感谢您的建议,但就像我在其他 cmets 中所说的那样,我的用户控件没有视图模型。我应该为我的 UserControl 创建一个视图模型吗?
  • 你有两种可能。首先:按照您的建议为您的 UserControl 创建一个 ViewModel。第二:将您的 UserControl 的 DataContext 设置为您的 MainWindowViewModel,以便您的 UserControl 可以访问您的 MainWindowViewModel 的属性。
  • 在第一种情况下,我应该使用 mvvm light 的 Messenger 将 usercontrol viewmodel 与 mainwindow viewmodel 进行通信还是有其他方法可以走?
  • mvvm light 的使者将是一个好方法,因为您可以保持 ViewModel 松散耦合。 (他们不需要互相认识。)
【解决方案2】:

MVVM 说,视图应该只与它的视图模型对话,而视图模型只能与其他视图模型(和模型)对话。
您需要的是调解员。
来源:http://dotnetpattern.com/mvvm-light-messenger/
有了这个,您不必在用户控件中创建事件。您可以与任何实例化的视图模型进行通信。 您可以使用 mvvm-light,它提供了 Mediator 模式(Messenger)的实现。它还提供了其他工具来帮助您构建 MVVM 应用程序。
here 是 MVVMLight Messenger 的教程。

通过绑定,您可以适当地更新视图。
因此视图模型相互对话,视图由相应的视图更新。
这样您就不会违反任何 MVVM 原则。

【讨论】:

  • 但是我的 UserControl 没有视图模型。 Messenger 仅用于在视图模型级别(视图模型到视图模型)上进行交谈。您是否建议我为我的 UserControl 创建一个视图模型?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-11
  • 1970-01-01
  • 2019-11-24
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多