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

时间:2010-04-14 13:23:49

标签: wpf user-controls mvvm dependency-properties

这就是我要做的事情:

  • 我正在编写一个我希望被其他开发人员使用的UserControl
  • 我希望最终用户能够使用依赖属性来使用我的控件。

    <lib:ControlView ControlsText={Binding Path=UsersOwnViewModelText} />
    
  • 我正在使用MVVM模式。

  • 我正在使用<DataTemplates>

    将我的ViewModel绑定到他们的View
    <DataTemplate DataType="{x:Type local:ControlViewModel}">  
        <local:ControlView />  
    </DataTemplate>
    

所以我有两个问题:

  1. 我认为如果在XAML中使用UserControl,那么当控件的DataContext事件触发而不是使用{{{}时,UserControl必须将ViewModel设置为其Loaded。 1}}方法?

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

4 个答案:

答案 0 :(得分:24)

您应该将两个用例分开:

  1. 其他开发人员将使用的(用户)控件。
  2. 您的应用程序将使用的用户控件。
  3. 重要的是,后者取决于前者 - 反之亦然。

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

    <强> MyControl.cs:

    public class MyControl : Control
    {
        // dependency properties and other logic
    }
    

    <强> Generic.xaml:

    <ControlTemplate Type="local:MyControl">
        <!-- define the default look in here, using template bindings to bind to your d-props -->
    </ControlTemplate>
    

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

    <强> MyViewModel.cs:

    public class MyViewModel : ViewModel
    {
        // properties and business logic
    }
    

    MyView.xaml:

    <UserControl ...>
        <local:MyControl SomeProperty="{Binding SomePropertyOnViewModel}" .../>
    </UserControl>
    

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

答案 1 :(得分:10)

首先,如果你正在开发一个将被其他人使用的UserControl,我认为MVVM不是一个好的选择。一个无形的控制是你真正应该开发的。 Jeremiah Morrill对这个问题有一个blog post

如上所述,如果您有默认的公共构造函数,可以使用XAML设置datacontext。

内部ControlView.xaml put:

<UserControl.DataContext>
    <local:ControlViewModel />
</UserControl.DataContext>

答案 2 :(得分:1)

UserControl是&#34; View&#34;的一部分。 in&#34; MVVM&#34;就像TextBoxListView控件是视图的一部分一样。

无论您是决定使用MVVM来开发UserControl本身还是在QBASIC中编写它(不推荐),只要它们可以做到,它就不会破坏UserControl的消费者的MVVM模式他们UserControl绑定到DependencyPropertyUserControl所带来的所有内容。即你的UserControl应该公开依赖的属性(因此名称)。一旦你掌握了这个DependencyProperty突然变得非常有意义,你希望他们对你在构造函数中指定的已更改的事件处理程序和默认值有所帮助。

如果你的UserControl在不同的装配中,我看不出它会有什么影响。

这就是说很多人会提倡你使用MVVM模式本身构建你的UserControl,因为MVVM带来了所有好的理由,例如:帮助其他开发人员查看您的代码。然而有些事情根本不可能和/或更难以更复杂且性能更差的黑客攻击XAML来做到这一点 - 我不是在讨论你的花园种类添加用户表单,但是例如UserControl处理成千上万的布局视觉效果。此外,由于您在View中工作,因此 NOT 希望将UserControl的ViewModel与您的应用程序混合在一起!

基本上我说MVVM很好,不在你的View上使用MVVM!

答案 3 :(得分:1)

基本上,不是将UserControl的datacontext绑定到userControlViewModel,而是最好在用户控件的第一个子元素上执行此操作。这样,您在控件中创建的所有引用都将绑定到userControlViewModel,但依赖项属性可以从您要使用UserControl的数据上下文集中设置。

这是我正在从事的一个项目:

<UserControl x:Class="Six_Barca_Main_Interface.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Six_Barca_Main_Interface"
             xmlns:System="clr-namespace:System;assembly=mscorlib" 
             mc:Ignorable="d" 
             d:DesignHeight="900" d:DesignWidth="900">

    <DockPanel  x:Name="rootDock" >
        <TextBlock>{Binding SomethingInMyUserControlViewModel}</TabControl>
    </DockPanel>
</UserControl>

然后在后面的代码:

public partial class MyUserControl : UserControl
{
    UserControlViewModel _vm;

    public MyUserControl()
    {
        InitializeComponent();

        //internal viewModel set to the first child of MyUserControl
         rootDock.DataContext = new UserControlViewModel();

        _vm = (UserControlViewModel)rootDock.DataContext;


        //sets control to be able to use the viewmodel elements

     }

     #region Dependency properties 
     public string textSetFromApplication
     {
         get{return (string)GetValue(textSetFromApplicationProperty);}
         set{SetValue(textSetFromApplicationProperty, value);}
     }

     public static readonly DependencyProperty textSetFromApplicationProperty = DependencyProperty.Register("textSetFromApplication", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, OnDependencyPropertyChanged));

     private static void  OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
        ((MyUserControl)d)._vm.SomethingInMyUserControlViewModel = 
             e.NewValue as string;
     }
#endregion

然后在主视图上使用它时,可以使用要传递给MyUSerControl的值设置依赖项属性