我的ViewModel上有一个依赖属性,它是我的View的DataContext。 ViewModel没有对View的引用。 ViewModel上的属性将引用视图上的控件,但我需要能够在XAML中设置此属性。
这怎么可能?我有一个想法是开发一个具有Property属性和Value属性的自定义控件,因此您可以在View中执行类似的操作以在ViewModel上设置属性:
<PropertySetter Property="{Binding MyViewModelDependencyProperty}" Value="{Binding ElementName=aControlOnMyView" />
在我走这条路之前,我想检查一下我是否还有其他办法吗?
感谢Ray的详细回复,但是如果我给你一些关于我试图解决的问题的更多细节,你可能会更好地了解我为什么提到我做的方法。
基本上,我要做的是在用户点击按钮时将焦点设置为文本框。我写了一个附加属性,你可以将它附加到Button控件,指定触发事件是什么(在这种情况下是'Click'事件),然后是要关注的控件。这非常有效,并且可以将所有内容保存在XAML中。
但是,我现在有一个用例,其焦点应设置为按钮上的单击事件的任意文本框,该按钮是工具栏的一部分。这个工具栏本身就是一个用户控件,它位于另一个用户控件内,该控件位于另一个用户控件内!此工具栏需要可以在各种不同的表单中重复使用,并且每次单击按钮后设置焦点的控件在每个表单中都会有所不同。
这就是为什么我想让焦点控件(即文本框)成为视图模型本身的属性(在我的ViewModel基础上是精确的),并且具有ViewModel基本代码(工具栏绑定到的) ,单击按钮时将焦点设置为控件(并在ViewModel基础上调用例如Add / Edit方法)。
在单元测试中,关注属性的控件将为null,因此不会调用.Focus()方法。所以我在那里看不到问题。我的问题是如何从XAML设置焦点控制属性,这就是为什么我有了PropertySetter的想法。
我不喜欢ViewModel对视图上的控件有任何引用这一事实,但我看不到另一种方法来实现我需要的东西。如果决定是否将焦点设置到控件的逻辑非常复杂怎么办?这肯定会在ViewModel中吗?因此,具有此UIElement属性的ViewModel是否有任何损害?它仍然对它所绑定的特定视图一无所知,它只知道在ViewModel上发生某些操作时需要将焦点设置为控件。
答案 0 :(得分:7)
我的第一反应(这是一个强烈反应)是这样说的“不要那样做!”通过为您的视图模型提供对UI的一部分的引用,您打破了使视图模型如此强大和有用的封装。
例如,如果要对视图模型进行单元测试或将其序列化为磁盘,该怎么办?在每种情况下,您的UI都不会出现,因为根本没有视图。您的测试将错过覆盖范围,您的重建将不完整。
如果您的视图模型实际上需要对UI对象的引用,并且没有更好的方法来构建它,那么最好的解决方案是让视图模型本身构造它需要引用的控件。然后,您的视图可以通过绑定将该控件合并为ContentPresenter的内容,并提供用于配置控件的Style,包括用于提供其内容的ControlTemplate。正是如此:
public class MyViewModel
{
public ListBox SpecialControl { get; set; }
public MyViewModel()
{
SpecialControl = new ListBox();
}
}
和
<DataTemplate TargetType="{x:Type local:MyViewModel}">
<DataTemplate.Resources>
<Style TargetType="ListBox" ... />
</DataTemplate.Resources>
...
<ContentPresenter Content="{Binding SpecialControl}" />
</DataTemplate>
其他可能性是:
我的选项#2看起来像这样:
<DataTemplate TargetType="{x:Type MyViewModel}">
...
<TextBox local:PropertyHelper.SetViewModelToThis="SpecialControl" />
...
</DataTemplate>
SetViewModelToThis PropertyChangedCallback中的代码将从DataContext获取视图模型,反映它以查找“SpecialControl”属性,然后将其设置为TextBox。请注意,SetViewModelToThis的实现必须考虑到DataContext没有立即设置的可能性,并且可能需要更改它,需要删除旧设置并创建一个新设置。
答案 1 :(得分:2)
首先,控件的DataContext
应该是ViewModel
对象,而不是它的属性。其次,当TwoWay
将ViewModel
的属性绑定到您的控件时,控件值的更改将更新(在您的情况下,'set')ViewModel
属性的值。