数据绑定到WPF中的UserControl

时间:2010-07-16 14:07:28

标签: c# wpf xaml wpf-controls

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

当我用静态文本(例如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 int。要获得TwoWay绑定,我需要在调用者中设置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 个答案:

答案 0 :(得分:12)

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

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

一旦加载并设置了所有Datacontext,它将在您的BlueTextBox事物控件中查找路径MyString,因为您将DataContext设置为它。我想这不是你打算如何工作的;)。

解决方案:

更改文本绑定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的构造函数,它应该像魅力一样工作..

答案 1 :(得分:2)

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

答案 2 :(得分:0)

可能需要添加到您的属性FrameworkPropertyMetadata,其中指定FrameworkPropertyMetadataOptions.AffectsRender和AffectsMeasure。

FrameworkPropertyMetadataOptions enumeration MSDN article

答案 3 :(得分:0)

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

在注册DP时,还要提及UIPropertyMetadata上的PropertyChangedCallback