【问题标题】:Binding to a custom property of a custom control property isn't working绑定到自定义控件属性的自定义属性不起作用
【发布时间】:2013-12-04 00:05:16
【问题描述】:

我正在开发一个自定义控件。我希望它支持数据绑定,因此它与内置控件一样易于维护。

这是我目前得到的:

  • 包含我的控件的窗口 Window.xaml 代码:

    <custom:Matrix x:Name="customMatrix" DockPanel.Dock="Top" Title="{Binding Title}"/>
    
  • ... 及其 Window.xaml.cs 代码隐藏(只是视图模型的一个片段)

    public ViewModel VM { get; private set; }
    
    private ProblemManager()
    {
        VM = new ViewModel();
    
        InitializeComponent();
    
        DataContext = VM;
        VM.Title = "a title";
    }
    
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public ViewModel()
        {
            ItemsList = new ObservableCollection<List<int>>();
        }
        public ObservableCollection<List<int>> ItemsList { get; set; }
    
        protected string title;
        public string Title
        {
            get { return title; }
            set
            {
                if (title != value)
                {
                    title = value;
                    NotifyPropertyChanged("Title");
                }
            }
        }
    
        protected void NotifyPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
    
  • 我的控件 Matrix.xaml

    // ...
    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}"/>
    // ...
    
  • 以及控件的 Matrix.xaml.cs 代码隐藏

    public partial class Matrix : UserControl
    {
        public Matrix()
        {
            InitializeComponent();
    
            DataContext = this;
        }
    
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(Matrix), new PropertyMetadata("", TitleChanged));
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
        private void TitleChanged(string title)
        {
            Title = title;
        }
        private static void TitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((Matrix)d).TitleChanged((string)e.NewValue);
        }
    }
    

问题是,如果不在我的窗口 xaml 中绑定到 Matrix.Title 属性,即在 xaml 中静态地赋予该值,如 Title="some title",我的控制代码中的绑定有效(我什至可以在我的窗口中执行 customMatrix.Title += "1";它有效)。但是,当绑定到Matrix.Title 属性时(就像我在提供的代码中所做的那样),它不起作用,并且我的视图中出现了一个空白标题。只是为了清楚地说明,绑定到窗口中的默认控件是有效的。

如何使 Matrix.Title 属性可绑定?

【问题讨论】:

    标签: wpf data-binding wpf-controls custom-controls


    【解决方案1】:

    您的 Matrix 控件上的 TextBlock 绑定错误。

    您已经设置了一个依赖属性,然后 Window.xaml 中的代码将该属性绑定到 Window 类中的 Title。这部分很好,尽管您不需要 TitleChanged 函数(绑定会自动完成,因此您不需要自己手动完成)。问题是您的 UserControl 中的 TextBlock.Text 属性是这样声明的:

    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}"/>
    

    所以它试图绑定到 UserControl 的当前 DataContext,如果你没有设置它(你显然没有),那么它从 MainWindow 继承它,它可能是也可能不是你想要的。要解决此问题,您需要将 TextBlock 绑定到 UserControl 的 属性,而不是 DataContext 属性,并且您可以使用 FindAncester 来做到这一点:

    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type custom:Matrix}}, Path=Title}" />
    

    更新:另一种方法是为 Matrix.xaml 文件中的 UserControl 命名并使用 ElementName 绑定到它:

    <UserControl x:Class="YourProjectNameHere.Matrix"
             xmlns:custom="clr-namespace:Wpftest2"
             ... more namespaces here
             mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" 
             Name="thisControl">
    <Grid>
        <TextBlock Name="theTextBlock" Grid.Row="0" Grid.Column="1" Text="{Binding ElementName=thisControl, Path=Title}"/>
    </Grid>
    

    【讨论】:

    • 没有在Matrix 构造函数中由DataContext = this; 指定我的控件的DataContext?
    • 噢!我什至没有看到 :) 但是,是的,这就是你的问题,你不能只是将 DataContext 更改为指向你想要的任何东西,因为当它放在主窗口上时,它会从你下方被更改出来。摆脱 TitleChanged 函数,删除在您的用户控件中分配数据上下文的那一行,并使用 FindAncestor 绑定,这将解决您的问题。
    • 你是说DataContext = this;赋值在我在其他地方使用控件时没有效果?不管怎样,我正在努力做你让我做的事情。将此绑定声明放在 Matrix.xaml 中会给我一个错误,即未定义 custom。确实不是,因为我在 Window.xaml 中使用 custom 作为我的 xaml 命名空间。我也尝试拥有x:Type Matrix,但没有运气。我现在缺少什么?
    • 我刚刚对此进行了一些测试,结果证明我错了,绑定在您手动将 DataContext 设置为“this”之前完成。无论如何,它仍然是不正确的,因为数据上下文需要正确设置为 ViewModel 才能使绑定在 MainWindow 上工作: 正如我所说,您需要摆脱“DataContext = this”语句并使用RelativeSource 绑定到UserControl。您收到的错误是因为您尚未包含“自定义”的命名空间。
    • 它必须在你的主窗口上,否则你会得到很好的错误(我假设你把你的控件拖到那个窗口上,它是自动生成的。看看你的主窗口 xaml对于这样的事情并将其添加到您的 Matrix xaml 中: xmlns:custom="clr-namespace:YourProjectName" 如果您仍然遇到问题,那么我已经用另一种实现此目的的方式更新了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2016-04-23
    • 2011-05-11
    • 2012-08-29
    • 2018-04-09
    • 2018-12-20
    • 1970-01-01
    • 2011-06-24
    相关资源
    最近更新 更多