WPF用户控制地狱与MVVM和依赖属性

Jon*_*ell 15 wpf user-controls dependency-properties mvvm

这就是我想要做的:

  • 我写的UserControl是我希望被其他开发者消费的.
  • 我希望最终用户能够使用依赖属性来使用我的控件.

    <lib:ControlView ControlsText={Binding Path=UsersOwnViewModelText} />
    
    Run Code Online (Sandbox Code Playgroud)
  • 我正在使用MVVM模式.

  • 我将我的ViewModels绑定到他们的View使用 <DataTemplates>

    <DataTemplate DataType="{x:Type local:ControlViewModel}">  
        <local:ControlView />  
    </DataTemplate>
    
    Run Code Online (Sandbox Code Playgroud)

所以我有两个问题:

  1. 我是否认为如果在XAML中使用UserControl,那么UserControl必须将ViewModel设置为DataContext控件Loaded事件触发时的方式而不是使用<DataTemplate>方法?

  2. 如何允许用户将数据绑定到我的控件的依赖项属性,同时仍然是绑定到我的ViewModel的数据?

Ken*_*art 25

您应该将两个用例分开:

  1. 其他开发人员将使用的(用户)控件.
  2. 应用程序将使用的用户控件.

重要的是,后者取决于前者 - 反之亦然.

用例1将使用依赖项属性,模板绑定,以及制作常规WPF控件的所有内容:

MyControl.cs:

public class MyControl : Control
{
    // dependency properties and other logic
}
Run Code Online (Sandbox Code Playgroud)

Generic.xaml:

<ControlTemplate Type="local:MyControl">
    <!-- define the default look in here, using template bindings to bind to your d-props -->
</ControlTemplate>
Run Code Online (Sandbox Code Playgroud)

然后,您将用例2定义为:

MyViewModel.cs:

public class MyViewModel : ViewModel
{
    // properties and business logic
}
Run Code Online (Sandbox Code Playgroud)

MyView.xaml:

<UserControl ...>
    <local:MyControl SomeProperty="{Binding SomePropertyOnViewModel}" .../>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

两个世界中最好的分离.其他开发人员只依赖于控件,控件可能(也可能应该)与视图模型和视图完全不同.


Bry*_*hle 10

首先,如果您正在开发一个将被其他人使用的UserControl,我认为MVVM不是一个好选择.一个无形的控制是你真正应该开发的.Jeremiah Morrill有一篇关于这个主题的博客文章.

话虽如此,如果您有默认的公共构造函数,可以使用XAML设置datacontext.

在ControlView.xaml里面放了:

<UserControl.DataContext>
    <local:ControlViewModel />
</UserControl.DataContext>
Run Code Online (Sandbox Code Playgroud)

  • -1将UserControl的viewmodel分配给XAML中的UserControl的DataContext将破坏尝试使用UserControl的DependencyProperties的父级的绑定.特别是对于OP <lib:ControlView ControlsText = {Binding Path = UsersOwnViewModelText} />中的这种绑定,它将导致绑定引用UserControl的viewmodel而不是父类.唯一的解决方法是让父母_somehow_知道这一点并使用ElementName绑定. (3认同)
  • 如前所述,在“ UserControl”中设置“ UserControl.DataContext”(无论如何完成)会覆盖上下文,否则该上下文将从最终使用控件的地方继承,从而导致绑定问题。如果需要ViewModel,我通常会在控件的最外部容器(通常是“ Grid”)上设置DC,而不是在“ UserControl”元素本身上进行设置。这样就可以继承控件本身的“ DataContext”(对于试图绑定到其DP的用户来说,不会感到惊讶),并且可以将ViewModel用作控件内部所有元素的常规用法。 (3认同)