绑定自定义依赖属性 - 再次

27
任务:实现最简单的依赖属性,可以在xaml中像这样使用:
<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>

我认为这个答案非常接近,为了更好地可读性,我在此处复制了大部分代码(主要是上面的答案)。

<UserControl x:Class="Test.UserControls.MyUserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <!-- Text is being bound to outward representative property;
             Note the DataContext of the UserControl -->
        <TextBox Text="{Binding MyTextProperty}"/>
    </Grid>
</UserControl>

并且

public partial class MyUserControl1 : UserControl
{
    // The dependency property which will be accessible on the UserControl
    public static readonly DependencyProperty MyTextPropertyProperty =
        DependencyProperty.Register("MyTextProperty", typeof(string), typeof(MyUserControl1), new UIPropertyMetadata(String.Empty));
    public string MyTextProperty
    {
        get { return (string)GetValue(MyTextPropertyProperty); }
        set { SetValue(MyTextPropertyProperty, value); }
    }

    public MyUserControl1()
    {
        InitializeComponent();
    }
}

这是我的MainWindow.xaml文件。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:uc="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <uc:MyUserControl1 MyTextProperty="my text goes here"/>
        <Button Click="ButtonBase_OnClick" Content="click"/>
    </StackPanel>
</Window>

目前,一切正常。然而,我觉得这并不太有用。我需要的是:

<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>

通过设置 DataContext(通常在 MVVM 中执行)来实现对此进行更改。

所以我将上述行替换,并添加以下代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        Text = "Initial Text";
        DataContext = this;
    }
    private string _Text;
    public string Text
    {
        get { return _Text; }
        set
        {
            if (value != _Text)
            {
                _Text = value;
                NotifyPropertyChanged("Text");
            }
        }
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        Text = "clicked";
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

“初始文本”和“点击”都没有显示……从来没有。所以我的问题是如何正确实现dept属性,以便与之一起使用。

<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>

1
你为什么回滚了这个更改?我只是添加了颜色到 C# 代码块,以便更容易阅读。 - NearHuscarl
1个回答

34

Text属性位于MainWindowDataContext中,而不是UserControl中。因此,请将此行:<uc:MyUserControl1 MyTextProperty="{Binding Text}"/>更改为以下内容:

<uc:MyUserControl1 MyTextProperty="{Binding Text, ElementName=MyMainWindow}"/>

这将告诉绑定器,你正在谈论位于你的 MainWindow 中的文本元素。当然,在这个例子中我使用了 ElementName,所以你需要给你的窗口起一个名字,比如叫 MyMainWindow…

因此,请在你的 MainWindow 中添加如下内容:

<Window  Name="MyMainWindow" ..... />

如果您不想为窗口命名,可以像这样使用RelativeSource FindAncestor绑定:

<wpfApplication6:MyUserControl1 MyTextProperty="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>
无论哪种方式,您都在请求在窗口的DataContext中查找名为“Text”的属性。

好的,非常感谢!通常我使用ViewModel,在后台代码中设置它,例如 'DataContext = new MyViewModel() {Text = "foo"}'。你能否详细说明如何设置绑定? - Martin Booka Weser
1
更新了我的答案,记住,如果Text不是一个依赖属性,那么MyViewModel应该实现INotifyPropertyChanged - Blachshma
再次感谢您的更新。您的更新在可视树中搜索窗口。但是,如何将绑定到DataContext,它可能不是控件,而是实现了INotifyPropertyChanged并用作MainWindow的DataContext的“普通”类?“AncestorType = MyViewModel”显然行不通... - Martin Booka Weser
我不确定我是否理解了这个场景。您有一个窗口,并将其DataContext设置为一些常规类,该类没有实现INotifyPropertyChanged接口?或者您是说您正在以非窗口方式使用此控件? - Blachshma
我在MyViewModel中实现了'Text'属性,它是一个普通类并且实现了INotifyPropertyChanged接口。在MainWindow的构造函数中,我执行了'this.DataContext = new MyViewModel()'。当我像我最初的问题所述那样在MainWindow中使用我的控件时,我想要使用MyViewModel.Text属性进行绑定,而不是MainWindow.Text。 - Martin Booka Weser
好的,抱歉。我找到了: MyTextProperty="{Binding Path=DataContext.Text, ElementName=MyMainWindow}" 无论如何,非常感谢!你应该得到点赞 :) - Martin Booka Weser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接