【问题标题】:Binding WPF element itself to view model object将 WPF 元素本身绑定到视图模型对象
【发布时间】:2018-08-11 02:21:53
【问题描述】:

我使用 MVVM 模式 向窗口中的用户控件提供数据。 我想在视图模型上实现一个方法对象,该对象将任何调用转发给它自己提供数据的相应的用户控件 .为此,我需要在视图模型对象中有一个对控件的引用

我可以通过在用户控件上声明一个属性来返回对控件本身的引用,然后绑定到视图模型对象来做到这一点,但这很丑:

<MyUserControl ReferenceToMyself="{Binding CorrespondingUserControl, Mode=OneWayToSource}"/>

然后在视图模型对象中:

public void MethodThatForwardsCalls() => CorrespondingUserControl.ThisIsCalled();

有没有更好的方法来将控件本身绑定到视图模型对象

【问题讨论】:

  • 不要那样做!如果您需要通知视图或调用方法以响应其他地方发生的事件,请考虑使用允许您发布和订阅事件的事件聚合器模式。
  • @slugster 谢谢,到目前为止我还没有听说过事件聚合器模式,值得一试!我不确定我将使用哪种解决方案,但这是一个有价值的信息,+1 去!

标签: c# wpf xaml mvvm data-binding


【解决方案1】:

您是否考虑过在 ViewModel 和 View 之间使用类似事件的交互来避免在 ViewModel 中保留对 View 的引用?

在 ViewModel 中,我将创建一个 Action 类型的属性,并将其命名为 ThisIsCalledEvent

#region ThisIsCalledEvent
        private Action m_ThisIsCalledEvent;
        public Action ThisIsCalledEvent
        {
            get
            {
                return m_ThisIsCalledEvent;
            }
            set
            {
                if (m_ThisIsCalledEvent != value)
                {
                    m_ThisIsCalledEvent = value;
                    OnPropertyChanged(nameof(ThisIsCalledEvent));
                }
            }
        }

#endregion

然后,在MyUserControl中,为DataContextChanged事件添加事件回调;

this.DataContextChanged += MyUserControl_DataContextChanged; 在 CS 构造函数中,或 DataContextChanged="MyUserControl_DataContextChanged" 在 XAML 构造函数中。

现在,在事件回调中,您可以为 ViewModel 的ThisIsCalledEvent 属性设置Action

private void MyUserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    MyUserControlViewModel vm = DataContext as MyUserControlViewModel; //Get the ViewModel from the View's DataContext

    if(vm == null)
        return;

    vm.ThisIsCalledEvent = delegate () { ThisIsCalled(); }; //When the action is invoked, call the desired function
}

现在,回到 ViewModel,调用您只需将方法的主体更改为;

public void MethodThatForwardsCalls()
{
    this.ThisIsCalledEvent?.Invoke(); //Invoke the Action, if it exists, that has been set by the View
}

这样,您永远不会在 ViewModel 中保留 View 的实例,并且每次从 ViewModel 实例化新视图时,它都会设置 Action 回调。

编辑 正如 Jürgen Röhr 在 cmets 中所建议的,在 DataContextChanged 事件回调中,您可以使用 args.NewValue 绑定到新的 DataContext。此外,如果您将代理注册到Action 属性而不是设置它,您可以使用args.OldValue 将其从之前的DataContext 中取消注册。

【讨论】:

  • 好一个。只需使用MyUserControl_DataContextChanged 中的args 参数注册到NewValue.ThisIsCalledEvent 并从'OldValue.ThisIsCalledEvent' 中注销。
  • Mark Diedericks 谢谢你,这个解决方案肯定能解决问题。实际上,slugster 在他们的回答中提到的 事件聚合器模式 是一种更优雅的方法,就我而言,我发现这种解决方法很有用。
  • @JürgenRöhr 感谢您非常重要的评论,这甚至不仅仅是一件微妙的事情,args.OldValue 对于取消订阅事件非常有用,可以防止发生内存泄漏!
猜你喜欢
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 2012-09-29
  • 2011-09-18
  • 2014-09-24
  • 2011-10-07
  • 1970-01-01
相关资源
最近更新 更多