WPF中用户控件的数据绑定

13
我有一个用户控件,想要参与数据绑定。我已经在用户控件中设置了依赖属性,但无法使其工作。
当我使用静态文本调用它时(例如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-->

我已将代码简化为以下示例。这是UserControl的XAML代码:
    <UserControl x:Class="Binding2.BlueTextBox" ...
    <Grid>
        <TextBox x:Name="myTextBox" Text="{Binding BlueText}" Foreground="Blue" Width="100" Height="26" />
    </Grid>

这是UserControl的后台代码:
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() ); }
    }

这似乎应该很容易,但我做不好。感谢您的帮助!

更多信息:当我尝试Eugene建议的修复方法时,我注意到了一些奇怪的行为。我向元数据添加了一个PropertyChangedCallback;这使我能够观察BlueText的值被设置。当将字符串设置为静态值(="感到忧郁")时,PropertyChanged事件会触发。数据绑定情况下不会触发PropertyChanged。我认为这意味着数据绑定的值没有发送到UserControl。(我认为在静态情况下构造函数不会被调用)

解决方案:Arcturus和jpsstavares正确地识别了问题。首先,在控件的构造函数中设置DataContext=this时,我正在覆盖数据绑定。这阻止了绑定的值被设置。我还必须将控件命名为x:Name=root,并在XAML中指定Binding ElementName=root。为了获得双向绑定,我需要在调用者中设置Mode=TwoWay。以下是正确的代码:

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

现在是UserControl中的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个回答

15

您将Control中的DataContext设置为自身,因此在其他控件中使用此Control时覆盖了DataContext。以您的绑定为例,在您的情况下:

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

一旦加载完成并且所有的Datacontext都设置好了,它将在您将DataContext设置为其后,查找BlueTextBox控件中的MyString路径。 我猜这不是您希望它工作的方式;).

解决方案:

更改文本绑定其中之一的2个绑定:

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

或者

将您的控件命名为Root(或类似名称)。

<UserControl x:Name="Root"

{Binding ElementName=Root, Path=BlueText}
并且移除
DataContext = this;

从您的UserControl的构造函数开始,它应该能够完美地工作。


3

我认为在这种情况下,您需要设置绑定中的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>

0

我知道这是一个老话题,但依然有价值。

同时在注册你的DP时记得在UIPropertyMetadata中提及PropertyChangedCallback。


0

尝试设置AffectsRender和AffectsMeasure,但这没有任何效果。谢谢。 - RaoulRubin

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