从 ViewModel 触发 UIElement 的操作
Posted
技术标签:
【中文标题】从 ViewModel 触发 UIElement 的操作【英文标题】:Triggering an action of a UIElement from a ViewModel 【发布时间】:2020-12-02 20:42:45 【问题描述】:我已经实现了Wiesław Šoltés'很棒的ZoomBorder,但我在 WPF 和 MVVM 方面有点挣扎。为了问题的完整性,ZoomBorder
是一个继承自Border
的UIElement
,并为用户提供了缩放和平移继承边框内容的可能性。它还可以重置缩放和平移。
我想让ZoomBorder
对某个视图模型发布的事件做出反应,以便在发布该事件时,ZoomBorder
重置缩放。在我的实现中,ZoomBorder
的DataContext
是一个ContentViewModel
,它有一个通过Autofac 注入的IEventAggregator
(Prism.Events)。理想情况下,我希望将事件聚合器直接注入ZoomBorder
,以便它可以订阅事件,但我不能,因为构造函数需要是无参数的。
所以ContentViewModel
必须订阅该事件,但我如何从ContentViewModel
调用ZoomBorder
的Reset
方法?我知道我会违反 MVVM,但我不知道该怎么做。我想过让ZoomBorder
通过依赖属性公开Command
,但是Reset
代码必须在视图模型上,但它不能。
【问题讨论】:
【参考方案1】:您可以在视图或控件中使用ServiceLocator
来解析容器中的类型。
public ZoomBorder()
_eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
如果您使用 AutoFac 和不带 Prism 的事件聚合器,则可以使用包 Autofac.Extras.CommonServiceLocator
和 register your container 到 ServiceLocator
。
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 方法。
【讨论】:
以上是关于从 ViewModel 触发 UIElement 的操作的主要内容,如果未能解决你的问题,请参考以下文章
WPF MVVM 从 ViewModel 触发事件的正确方法
我的活动中的 ViewModel.Observe() 函数没有触发
Knockout ViewModel 在 ajax 之后被更新,但我的 foreach 没有被触发
从 StackPanel C# UWP 中选择图像(将动作侦听器添加到 UIElement 并将图像添加到 UIElement)