依赖属性绑定不更新目标

时间:2010-06-17 17:38:55

标签: c# wpf dependencies dependency-properties

我有一个自定义依赖项属性:

    public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("HeaderProperty", typeof(string), typeof(RadAdjustableSlider));
    public string Header
    {
        get
        {
            return (string)GetValue(HeaderProperty);
        }
        set
        {
            SetValue(HeaderProperty, value);
        }
    }

然后我在我的xaml中有一个绑定:

<TextBlock Name="txtHeader" Text="{Binding ElementName=main, Path=Header, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />

请注意,我在xaml文件顶部的声明中也有这个:

         x:Name="main"

最后,我有这个构造函数:

    public RadAdjustableSlider()
    {
        InitializeComponent();
        this.Header = "Header";
    }

当我将此控件放在另一个父控件中时,Header文本块为空。为什么呢?

修改:This blog说这样做的正确方法是在DependencyProperty.Register调用中提供ValidateValueCallback,但这似乎有点管道而且没有解释依赖属性在与外部控件交互时的行为方式。我真的要为所有依赖属性编写回调函数吗?

2 个答案:

答案 0 :(得分:1)

框架中有一个HeaderedContentControl和HeaderedItemsControl ......

但是如果你真的想创建自己的,那么你应该使用TemplateBinding。尝试这样的事情:

class MyHeaderedControl : ContentControl
{
  public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
    "Header",
    typeof(object),
    typeof(MyHeaderedControl),
    new PropertyMetadata());

  public MyHeaderedControl()
  {
    this.DefaultStyleKey = typeof(MyHeaderedControl);
  }
}

然后在您的项目中创建一个“\ Themes \ Generic.xaml”文件。这是一个特别命名的文件,必须位于项目的根目录,然后在Themes文件夹中。它必须包含ResourceDictionary。

<ResourceDictionary
  xmlns="..."
  xmlns:x="..."
  xmlns:c="MyControlLibrary1"
  >
  <Style TargetType="{x:Type c:MyHeaderedControl>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type c:MyHeaderedControl}">
          <StackPanel>
            <ContentControl Content="{TemplateBinding Header}" />
            <ContentPresenter /> 
          </StackPanel>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

此外,在AssemblyInfo.cs中添加此属性(如果它尚未存在):

[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, 
       ResourceDictionaryLocation.SourceAssembly)]

所以概述。一般的想法是创建某种类型的逻辑控件,其中包含属性和事件以及逻辑等。然后在同一个程序集中提供默认主题。这就是默认情况下控件的显示方式。在使用控件的任何地方,都可以覆盖默认模板,并且可以像往常一样覆盖特定模板。

所以这是最无痛的方式,您可以将自定义内容添加到自定义控件中!尝试一次它会有意义,而不是感觉到cludgy。如果您制作更多控件,请继续将它们添加到Generic.xaml文件中。

答案 1 :(得分:0)

正如上面提到的justin.m.chase,自定义控件可能是最好的方法,但UserControls是一种常见的场景,所以我还是会添加我的2c。

UserControl不会为您设置DataContent属性,因此UserControl XAML中的所有绑定都会解析为放置控件的DataContent。

要更改此行为,请在usercontrol构造函数中设置DataContext属性:

public RadAdjustableSlider()
{
    InitializeComponent();
    this.Header = "Header";

    this.DataContext = this;
}

然后像这样绑定:

<TextBlock Text="{Binding Header}" />

或者不设置DataContext并像这样绑定:

<TextBlock Text="{Binding Header, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ns:RadAdjustableSlider}}}" />