代码之家  ›  专栏  ›  技术社区  ›  RaoulRubin

数据绑定到WPF中的用户控件

  •  11
  • RaoulRubin  · 技术社区  · 14 年前

    我有一个要参与数据绑定的用户控件。我已经在用户控件中设置了依赖项属性,但无法使其正常工作。

    当我用静态文本(例如bluetext=“abc”)调用它时,UC显示正确的文本。当我试图将其绑定到本地公共财产时,它总是空白的。

    <src:BlueTextBox BlueText="Feeling blue" />            <!--OK-->
    <src:BlueTextBox BlueText="{Binding Path=MyString}" /> <!--UserControl always BLANK!-->
    <TextBox Text="{Binding Path=MyString}" Width="100"/>  <!--Simple TextBox Binds OK-->
    

    我将代码简化为以下简化示例。下面是用户控件的XAML:

        <UserControl x:Class="Binding2.BlueTextBox" ...
        <Grid>
            <TextBox x:Name="myTextBox" Text="{Binding BlueText}" Foreground="Blue" Width="100" Height="26" />
        </Grid>
    

    下面是用户控件背后的代码:

    public partial class BlueTextBox : UserControl
    {
        public BlueTextBox()
        {
            InitializeComponent(); 
            DataContext = this; // shouldn't do this - see solution
        }
    
        public static readonly DependencyProperty BlueTextProperty =
            DependencyProperty.Register("BlueText", typeof(string), typeof(BlueTextBox));
    
        public string BlueText
        {
            get { return GetValue(BlueTextProperty).ToString(); }
            set { SetValue( BlueTextProperty, value.ToString() ); }
        }
    

    这似乎很容易,但我做不到。谢谢你的帮助!

    更多信息:当我尝试尤金建议的修复方法时,我注意到一些特殊的行为。我在元数据中添加了一个propertyChangedCallback;这允许我观察BlueText的设置值。当将字符串设置为静态值(=“feeling blue”)时,将触发PropertyChanged事件。数据绑定事例不会激发PropertyChanged。我认为这意味着数据绑定值不会被发送到用户控件。(我认为在静态情况下不会调用构造函数)

    解决方案: 这些问题由Arcturus和JPSStavares正确识别。首先,当在控件的构造函数中设置dataContext=this时,我正在重写数据绑定。这阻止了数据绑定值的设置。我还必须命名控件x:name=root,并在XAML中指定binding elementname=root。要获得twoway绑定,我需要在调用者中设置mode=twoway。以下是正确的代码:

    <src:BlueTextBox BlueText="{Binding Path=MyString, Mode=TwoWay}}" /> <!--OK-->
    

    现在,用户控件中的XAML:

        <UserControl x:Class="Binding2.BlueTextBox" x:Name="root"...
        <Grid>
            <TextBox x:Name="myTextBox" Text="{Binding ElementName=root, Path=BlueText}" Foreground="Blue" Width="100" Height="26" />
        </Grid>
    

    最后,我在UserControl的构造函数中删除了dataContext=this。

        public BlueTextBox()
        {
            InitializeComponent(); 
            //DataContext = this; -- don't do this
        }
    

    感谢大家的大力帮助!

    4 回复  |  直到 6 年前
        1
  •  12
  •   Arcturus    14 年前

    将控件中的DataContext设置为自身,从而在其他控件中使用此控件时覆盖DataContext。以您的绑定为例:

    <src:BlueTextBox BlueText="{Binding Path=MyString}" /> 
    

    一旦加载并设置了所有DataContext,它将在BlueTextBox对象控件中查找路径myString,因为您将DataContext设置为它。我想这不是你想要的工作方式;)。

    解决方案:

    更改文本绑定2个绑定中的任意一个:

    {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:BlueTextBox}}, Path=BlueText}
    

    命名控件根(或类似的名称)

    <UserControl x:Name="Root"
    
    {Binding ElementName=Root, Path=BlueText}
    

    并移除

    DataContext = this;
    

    从你的用户控件的构造器,它应该像一个魅力。

        2
  •  2
  •   jpsstavares    14 年前

    我认为在这种情况下,你需要设置 ElementName 绑定中的属性。像这样:

    <UserControl x:Class="Binding2.BlueTextBox" x:Name="blueTextBox"...
    <Grid>
        <TextBox x:Name="myTextBox" Text="{Binding ElementName=blueTextBox, Path=BlueText}" Foreground="Blue" Width="100" Height="26" />
    </Grid>
    
        3
  •  0
  •   Eugene Cheverda    14 年前

    可能需要将添加到属性frameworkpropertiesmetadata中,其中指定frameworkpropertiesmetadaatooptions.affectsrender和affectsMeasure。

    FrameworkPropertyMetadataOptions enumeration MSDN article

        4
  •  0
  •   Jordy van Eijk    13 年前

    我知道这是一个古老的话题,但仍然如此。

    在注册DP期间,还应在uipropertymetadata上提到propertychangedcallback。