【问题标题】:Triggering an action of a UIElement from a ViewModel从 ViewModel 触发 UIElement 的操作
【发布时间】:2020-12-02 20:42:45
【问题描述】:

我已经实现了Wiesław Šoltés'很棒的ZoomBorder,但我在 WPF 和 MVVM 方面有点挣扎。为了问题的完整性,ZoomBorder 是一个继承自BorderUIElement,并为用户提供了缩放和平移继承边框内容的可能性。它还可以重置缩放和平移。

我想让ZoomBorder 对某个视图模型发布的事件做出反应,以便在发布该事件时,ZoomBorder 重置缩放。在我的实现中,ZoomBorderDataContext 是一个ContentViewModel,它有一个通过Autofac 注入的IEventAggregator (Prism.Events)。理想情况下,我希望将事件聚合器直接注入ZoomBorder,以便它可以订阅事件,但我不能,因为构造函数需要是无参数的。

所以ContentViewModel 必须订阅该事件,但我如何从ContentViewModel 调用ZoomBorderReset 方法?我知道我会违反 MVVM,但我不知道该怎么做。我想过让ZoomBorder 通过依赖属性公开Command,但是Reset 代码必须在视图模型上,但它不能。

【问题讨论】:

    标签: wpf mvvm dependency-injection prism uielement


    【解决方案1】:

    您可以在视图或控件中使用ServiceLocator 来解析容器中的类型。

    public ZoomBorder()
    {
       _eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
    }
    

    如果您使用 AutoFac 和不带 Prism 的事件聚合器,则可以使用包 Autofac.Extras.CommonServiceLocatorregister your containerServiceLocator

    var builder = new ContainerBuilder();
    var container = builder.Build();
    
    var csl = new AutofacServiceLocator(container);
    ServiceLocator.SetLocatorProvider(() => csl);
    

    【讨论】:

      【解决方案2】:

      我会使用绑定。

      为 Zoomborder 添加一个依赖属性。

          public bool? ResetZoom
          {
              get
              {
                  return (bool?)GetValue(ResetZoomProperty);
              }
              set
              {
                  SetValue(ResetZoomProperty, value);
              }
          }
          public static readonly DependencyProperty ResetZoomProperty =
              DependencyProperty.Register("ResetZoom",
                          typeof(bool?),
                          typeof(CloseMe),
                          new PropertyMetadata(null, new PropertyChangedCallback(ResetZoomChanged)));
          private static void ResetZoomChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
          {
              if ((bool?)e.NewValue != true)
              {
                  return;
              }
              ZoomBorder zb = (ZoomBorder)d;
              zb.Reset();
              zb.SetCurrentValue(ResetZoomProperty, false);
          }
      

      然后,您可以将其绑定到 ContentViewModel 中的公共 bool 属性。

      设置为 true 时,边框将重置。

      【讨论】:

      • 谢谢。我考虑过这个选项(很抱歉在问题中没有提到它),但它并没有让我相信将它设置为 false 没有任何效果。这就像你要为实际上不是一个状态的东西维护一个状态,而更像是一个做某事的信号。
      • 将其设置为 false 会被显式捕获,因此绝对没有效果。是的,它是做某事的信号,但使用简单的标准 wpf 机制。
      【解决方案3】:

      本视频展示了如何从视图/UI 组件创建抽象,并使用接口从 VM 调用它们的方法。不要让标题欺骗你。这看起来非常适合这种情况

      “如何在 C# 中从 ViewModel 关闭窗口”

      https://youtu.be/U7Qclpe2joo

      除了在窗口上调用 Close 方法外,您还可以调整它以从 VM 调用控件上的 Reset 方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 2020-05-23
        • 1970-01-01
        相关资源
        最近更新 更多