MVVM + UserControl + 依赖属性

7
好的,这与以下问题有关:WPF从单个视图模型打印多个页面
我试图按照那里给出的建议进行操作,但现在我卡住了。
我的应用程序使用MainView.xaml和相应的MainViewViewModel.cs,我在后台使用MVVM Light。
现在-根据帖子-似乎我必须执行以下操作:
  • 创建一个用户控件
  • 从用户控件公开一些属性
  • 确保视图模型显示这些属性
这个想法很清楚,但当我尝试相互通知时就卡住了。
我的用户控件(UcTest.xaml)公开了一个依赖属性:
public string SpecialText
{
    get { return (string)GetValue(SpecialTextProperty); }
    set
    {
        SetValue(SpecialTextProperty, value);

    }
}

// Using a DependencyProperty as the backing store for SpecialText.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty SpecialTextProperty =
    DependencyProperty.Register("SpecialText", typeof(string), typeof(UcTest), new PropertyMetadata(new PropertyChangedCallback(SpecialTextChangedPropertyCallback)));

private static void SpecialTextChangedPropertyCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    // Do something
    Debug.WriteLine("Ffgdgf");
}

好的,现在我有一个用户控件,其中包含一些依赖属性。然而,这些属性与我的ViewModel属性完全分离(这些属性将被显示)。

所以基本上我有两种可能:

  • 现在我如何告诉我的UserControl的ViewModel一些属性已经改变了?
  • 是否有一种方法可以忘记依赖属性并直接访问ViewModel?

附加信息#1: 我上传了一个(简单的)示例,展示我想要做的事情:示例项目。我希望从MainViewViewModel更改UserControl1中标签的值(通过UserControl1的ViewModel的绑定属性)。


1
这意味着我的UserControl需要实现INotifyPropertyChanged,这基本上是我的ViewModel应该做的事情。 - Tom L.
2个回答

5

好的,在经过数小时的谷歌搜索后,似乎“正确”的方法是根本不要这样做。通常的做法是将数据保存在MainViewModel中,而不使用额外的UserControl ViewModel(我觉得有点...嗯...不太好)。主要问题是没有简单的机制可以将依赖属性中的数据传递到ViewModel。

至于打印,我现在已经完全改为纯编码实现。


这可能适用于将选项卡项目分离为用户控件的情况。但是对于像文件浏览器这样显示多次的通用控件呢? - bytecode77
@Tom L. 在你的情况下,我能想到的最好方法是不在用户控件中设置数据上下文,然后在窗口加载时将传递的属性从 DP 保存到变量中,然后将上下文设置为 VM 的新实例。然后设置 VM 中的正确属性并继续进行。这不是理想的解决方案,但它确实完成了工作。我希望在 DP 的元数据中,您可以指定获取绑定的上下文。 - TK-421

5

通常情况下,您会将UserControl的属性与ViewModel的属性进行绑定。双向绑定可以在ViewModel到View和反之间同时起作用。

<Window x:Class="TestApplication.MainWindow" ...>
    <Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>
    <Grid>
        <local:UcTest SpecialText="{Binding MyViewModelProperty, Mode=TwoWay}"/>
    </Grid>
</Window>

在上面的示例中,要直接访问ViewModel对象,您可以将UserControl的DataContext属性强制转换为ViewModel类型。 DataContext从MainWindow继承。
var viewModel = DataContext as MyViewModel;
var property = viewModel.MyViewModelProperty;

当然,您也可以直接将专门的ViewModel实例分配给UserControl的DataContext

<local:UcTest SpecialText="{Binding MyViewModelProperty, Mode=TwoWay}"/>
    <local:UcTest.DataContext>
        <local:UserControlViewModel/>
    </local:UcTest.DataContext>
</local:UcTest>

或者,您可以在资源字典中创建ViewModel实例,并像这样分配DataContext。
<local:UcTest DataContext="{StaticResource MyUserControlViewModel}"
              SpecialText="{Binding MyViewModelProperty, Mode=TwoWay}"/>

1
嗯,我想我可能误解了你的意思。问题在于UserControl有自己的ViewModel,我想要将其绑定到它。或者您认为最好将属性保留在MainViewModel中,只是使用没有自己的ViewModel的UserControl? - Tom L.
这取决于您的应用程序设计。两种方法都是有效的解决方案。您也可以直接分配UserControl的DataContext属性。 - Clemens
1
嗯,我不太理解这个。你能否提供一个示例?因为一旦我将UserControl的DataContext更改为UserControlViewModel,我就无法再分配任何变量,因为UserControl不知道这些属性。 如果SpecialText不是DependencyProperty,我该如何将其分配给某个值? - Tom L.
看我的编辑。你说的“如果SpecialText不是DependencyProperty,我怎么能将某些东西分配给它?”是什么意思?SpecialText是一个依赖属性,你已经按照这种方式设计了它。 - Clemens
1
是的(哦,这很难解释)。主要的点是依赖属性“特殊文本”与ViewModel解耦。我已经上传了一个小例子(链接在我的主帖中),可能可以演示我的意思。 - Tom L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接