【问题标题】:How to set DataBinding for UserControl with ViewModel如何使用 ViewModel 为 UserControl 设置 DataBinding
【发布时间】:2019-03-25 14:30:26
【问题描述】:

我有一个用户控件,里面有几个控件。所以我决定使用 ViewModel 来管理所有这些可绑定的值。但我发现我的绑定总是空的。那么如何在用户控件中为 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 视图模型)

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

Wizard.xaml(我的用户控件)

<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 始终为空。那么如何在 UserControl 中设置这个 ViewModel

【问题讨论】:

  • &lt;cus:Wizard DataContext="{Binding MyModel}"/&gt;
  • UserControl 通常不应该有自己的“私有”视图模型。它永远不应该显式设置自己的 DataContext,而是对它从其父元素继承的 DataContext 进行操作,例如主窗口。最灵活的方法是通过暴露(可绑定的)依赖属性使其完全独立于任何特定的视图模型类,如图所示。这里:stackoverflow.com/a/53480682/1136211
  • @AbinMathew 这行得通,但这会使我的 WizardModel 无用
  • 您的 WizardModel 在设计上毫无用处。但是,要回答您的实际问题,WizardModel="{Binding MyModel}" 需要当前 DataContext 中的 MyModel 属性,您已将其显式设置为 CurrentModel。它只是行不通。您绝不能显式设置 UserControl 的 DataContext,否则任何标准的、基于 DataContext 的绑定将不再起作用。
  • @Clemens 这可能适用于一个绑定,对吗?假设我有多个文本框并且它们都是可绑定的,它们也可以更新吗?

标签: c# wpf user-controls


【解决方案1】:

应该对特定视图模型类(或更准确地说是对具有一组特定公共属性的类)进行操作的 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}"/>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 2016-12-22
    • 2018-06-13
    • 2018-09-16
    • 2019-03-24
    • 1970-01-01
    相关资源
    最近更新 更多