将 DependencyProperty 转发给包含在用户控件中的控件

3

我正在尝试制作一个用户控件,其中包含一些 DependencyProperties, 这些属性会被转发给用户控件中的子控件。经过几次尝试,我终于让它工作了。为了测试,我做了一个小例子。

在这个例子中,我有一个名为 Ctrl 的用户控件,它只包含一个 TextBox 并公开了 TextBoxText 属性。这个控件用在一个窗口中,该窗口包含了一个 TextBox 和我的自定义 Ctrl,它们都绑定到同一个属性上。

用户控件

XAML

<UserControl x:Class="trying.Ctrl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource self}}"
    Height="Auto" Width="Auto">
    <TextBox Text="{Binding MyText}" />
</UserControl>

代码后台

using System.Windows;
using System.Windows.Controls;

namespace trying
{
    public partial class Ctrl : UserControl
    {
        public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register(
            "MyText",
            typeof( string ),
            typeof( UserControl ),
            new FrameworkPropertyMetadata( default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
        public string MyText
        {
            get { return (string)GetValue( MyTextProperty ); }
            set { SetValue( MyTextProperty, value ); }
        }

        public Ctrl()
        {
            InitializeComponent();
        }
    }
}

窗口

XAML

<Window x:Class="trying.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cc="clr-namespace:trying"
    DataContext="{Binding RelativeSource={RelativeSource self}}"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding DisplayText}" />
        <cc:Ctrl Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" MyText="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DisplayText}" />
    </Grid>
</Window>

后端代码

using System.Windows;
using System.ComponentModel;

namespace trying
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged( string propertyName )
        {
            if( PropertyChanged != null )
                PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
        }

        private string m_displayText = "asdf";
        public string DisplayText
        {
            get { return m_displayText; }
            set
            {
                m_displayText = value;
                NotifyPropertyChanged( "DisplayText" );
            }
        }

        public Window1()
        {
            InitializeComponent();
        }
    }
}

问题

当我发布代码后它可以正常工作,但现在我的问题是:我做错了什么导致我需要使用绑定?

 MyText="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}

当绑定CtrlMyText属性时,不能像绑定原始的TextBox那样简单地绑定。如果不这样绑定,它将无法工作,并出现警告。

  System.Windows.Data Error: 39 : BindingExpression path error: 'DisplayText' property
  not found on 'object' ''Ctrl' (Name='')'. BindingExpression:Path=DisplayText; 
  DataItem='Ctrl' (Name=''); target element is 'Ctrl' (Name=''); target property
  is 'MyText' (type 'String')

我需要如何更改才能实现与原始的TextBox相同的绑定?

在执行期间。

1个回答

2
UserControlDataContext 指向自身,因此对控件实例的任何绑定都将查看 Ctrl 实例而不是继承的 DataContext。尝试在树形结构中进一步设置 DataContext
<UserControl 
   x:Class="trying.Ctrl" x:Name="root"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Height="Auto" Width="Auto"
>
   <TextBox 
      DataContext="{Binding ElementName=root}"
      Text="{Binding MyText}" 
   />
</UserControl>

谢谢,这个方法有效。我的想法对吗:由于绑定是Ctrl的'content',所以它会在它的上下文中被评估。因此,正如你所说,本地的DataContext适用。如果我在Ctrl中有一个Grid,我可以在此Grid上设置DataContext,因为绑定发生在Ctrl中的UserControl中。我的设置DataContext的方式只应该用于Window等,不适用于UserControl - Andreas Wallner
是的,如果你在Grid上设置了DataContext,UserControl上的绑定将使用继承的DataContext,而Grid或Grid的任何子元素上的绑定将使用新的DataContext。 - Richard Deeming

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