使用一个DependencyProperty在UserControl中绑定具有多个属性的模型

时间:2018-05-14 22:53:25

标签: c# wpf xaml data-binding

我希望能够通过UserControl将复杂模型(许多属性)绑定到DependencyProperty,如果在UserControl中编辑模型,我希望看到此编辑的信息在我的绑定模型中。

示例应用程序:Model,UserControl(xaml + cs),MainWindow(xaml + cs)。我没有ViewModel来简化想法。

型号:

public class MyModel : INotifyPropertyChanged
{
    private string _surname;
    private string _name;

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public string Surname
    {
        get => _surname;
        set
        {
            _surname = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MyModelEditor.xaml(在Grid中):

<DockPanel>
    <TextBox Text="{Binding MyModel.Name}"/>
    <TextBox Text="{Binding MyModel.Surname}"/>
</DockPanel>

在UserControl根元素中还包含此行: DataContext="{Binding RelativeSource={RelativeSource Self}}"

MyModelEditor.xaml.cs:

public partial class MyModelEditor : UserControl
{
    public MyModel MyModel
    {
        get => (MyModel)GetValue(MyModelProperty);
        set => SetValue(MyModelProperty, value);
    }

    public static readonly DependencyProperty MyModelProperty =
        DependencyProperty.Register("MyModel", typeof(MyModel), typeof(MyModelEditor), new FrameworkPropertyMetadata(null));

    public MyModelEditor()
    {
        InitializeComponent();
    }
}

MainWindow.xaml(在Grid中):

<DockPanel>
    <Button DockPanel.Dock="Bottom" Content="Press Me!" Click="ButtonBase_OnClick"/>
    <controls:MyModelEditor MyModel="{Binding MyModel}"/>
</DockPanel>

MainWindow.xaml.cs:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private MyModel _myModel;

    public MyModel MyModel
    {
        get => _myModel;
        set
        {
            _myModel = value;
            OnPropertyChanged();
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        MessageBox.Show(MyModel?.Name);
    }
}

我的测试场景:在文本框中键入文本,按下按钮。
当前行为:按下按钮后的消息为空 预期行为:按下按钮后的消息与文本框中的消息相同。

我不想分别绑定到所有属性,因为将来我会有两个以上的属性。

为什么目前的做法不起作用? 我怎样才能实现目标?

2 个答案:

答案 0 :(得分:3)

您显然没有在UserControl的XAML中将UserControl实例用作绑定源。一种方法是设置Binding的RelativeSource:

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

但是,为此,您根本不需要新的依赖项属性。只需将UserControl的DataContext绑定到MyModel实例,例如

<controls:MyModelEditor DataContext="{Binding MyModel}"/>

UserControl的XAML中的Bindings会自动使用MyModel对象,如下所示:

<DockPanel>
    <TextBox Text="{Binding Name}"/>
    <TextBox Text="{Binding Surname}"/>
</DockPanel>

答案 1 :(得分:1)

对于您的两个TextBox控件,您应该在绑定模式下使用Binding模式(ms docs)定义他们的TwoWay。基本上,这将确保数据流在两个方向上工作(即从视图模型到视图,反之亦然):

<DockPanel>
    <TextBox Text="{Binding MyModel.Name, Mode=TwoWay}"/>
    <TextBox Text="{Binding MyModel.Surname, Mode=TwoWay}"/>
</DockPanel>

作为一种良好做法,您应该始终明确定义Binding的模式(注意:默认情况下,它是 OneWay TwoWay - how to know which is the default?)。

另一个提示是继续使用MvvmHelpers nugetgithub project),这可以免除您实施INotifyPropertyChanged的时间。此外,你不应该重新发明轮子

编辑 :修复程序位于您的GitHub存储库中

这里要注意两件事

  1. 您尚未实例化您的ViewModel(即MyModel),因此始终为null
  2. 每次要将某些信息传递给DependencyPropery时,您无需创建UserControl。您可以简单地绑定DataContext本身