如何使用ViewModel为UserControl设置DataBinding

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用ViewModel为UserControl设置DataBinding相关的知识,希望对你有一定的参考价值。

我有一个usercontrol里面有几个控件。所以我决定使用ViewModel来管理所有那些可绑定的值。但我发现我的绑定始终为空。那么如何在usercontrol中为ViewModel设置绑定

MainWindows.xaml

<Window x:Class="Test.MainWindow"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <cus:Wizard WizardModel="{Binding MyModel}"/>
    </StackPanel>
</Window>

MainWindows.xaml.cs

public partial class MainWindow : Window
{
   private ViewModel vm = new ViewModel();
   public MainWindow()
   {
        InitializeComponent();
        DataContext = vm;
   }
}

ViewModel.cs(MainWindow viewmodel)

    public class ViewModel : INotifyPropertyChanged
    {
        private Model _MyModel;
        public Model MyModel
        {
            get
            {
                return _MyModel;
            }
            set
            {
                _MyModel = value;
                NotifyPropertyChanged("MyModel");
            }
        }
    }

Wizard.xaml(我的UserControl)

<UserControl mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Something}" />
    </Grid>
</UserControl>

Wizard.xaml.cs

public partial class Wizard : UserControl
{
    private readonly object modelLock = new object();
    private Model CurrentModel = new Model();
    public Wizard()
    {
        InitializeComponent();
        DataContext = CurrentModel;
    }     
    public Model WizardModel
    {
        get { return (Model)this.GetValue(WizardModelProperty); }
        set { this.SetValue(WizardModelProperty, value); }
    }
    public static readonly DependencyProperty WizardModelProperty = DependencyProperty.Register("WizardModel", typeof(Model), typeof(Wizard), new PropertyMetadata(null, new PropertyChangedCallback(ModelChanged)));
    private static void ModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((Wizard)d).OnModelChanged();
    }
    private void OnModelChanged()
    {
        lock (this.modelLock)
        {
            if(CurrentModel != null)
            {
                CurrentModel = null;
            }
            if (WizardModel != null)
            {
                CurrentModel = WizardModel;                    
            }
        }
    }
}

UserControl中的WizardModel始终为null。那么如何在UserControl中设置这个ViewModel

答案

应该在特定视图模型类上操作的UserControl - 或者更确切地说,在具有特定公共属性集的类上操作 - 可以直接绑定到其XAML中的视图模型属性。

鉴于一个视图模型

public class Model
{
    public string Something { get; set; }
}

你可以写一个只有这个XAML的UserControl

<UserControl ...>
    ...
    <TextBox Text="{Binding Something}" />
    ...
</UserControl>

而这个代码背后

public partial class Wizard : UserControl
{
    public Wizard()
    {
        InitializeComponent();
    }  
}

如果现在将其DataContext设置为Model(或具有Something属性的任何其他类)的实例,它将起作用:

<local:Wizard DataContext="{Binding MyModel}"/>

由于DataContext属性的值从父元素继承到子元素,因此这也将起作用:

<StackPanel DataContext="{Binding MyModel}">
    <local:Wizard/>
</StackPanel>

但是,UserControl仍然依赖于其DataContext中存在Something属性。为了摆脱这种依赖性,你的控件可能会暴露一个依赖属性

public static readonly DependencyProperty MyTextProperty =
    DependencyProperty.Register(nameof(MyText), typeof(string), typeof(Wizard));

public string MyText
{
    get { return (string)GetValue(MyTextProperty); }
    set { SetValue(MyTextProperty, value); }
}

并将其XAML中的元素绑定到自己的属性

<UserControl ...>
    ...
    <TextBox Text="{Binding MyText,
        RelativeSource={RelativeSource AncestorType=UserControl}}"/>
    ...
</UserControl>

现在,您将绑定控件的属性,而不是设置其DataContext:

<local:Wizard MyText="{Binding MyModel.Something, Mode=TwoWay}"/>

以上是关于如何使用ViewModel为UserControl设置DataBinding的主要内容,如果未能解决你的问题,请参考以下文章

将 IsEnabled 绑定到父 ViewModel 而不是 UserControl ViewModel

将参数传递给 UserControl viewmodel

Usercontrol - 从 ViewModel 通知属性更改

将UserControl绑定到ViewModel(Caliburn Micro WPF)

DataContext 用于在 DataTemplate 中将 UserControl 与 ViewModel 绑定

将 ViewModel 的属性绑定到 UserControl 的子控件和自身的 DependencyProperty