属性值继承不与UserControl一起使用

时间:2012-04-10 14:20:09

标签: wpf dependency-properties

我正在尝试利用从窗口到UserControl的属性值继承。据我所知,您可以通过声明附加的DependencyProperty(与FrameworkPropertyMetadataOptions.Inherits选项一起)来实现此目的。

MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:WpfApplication1" Name="BobWindow">
    <Grid>
        <Label Content="MainWindow" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="85,2,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Test, ElementName=BobWindow}" />
        <my:UserControl1 HorizontalAlignment="Left" Margin="157,108,0,0" x:Name="userControl11" VerticalAlignment="Top" />
    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public static readonly DependencyProperty TestProperty = DependencyProperty.RegisterAttached
            (
                "Test",
                typeof(String),
                typeof(MainWindow),
                new FrameworkPropertyMetadata
                    (
                        null,
                        FrameworkPropertyMetadataOptions.Inherits
                    )
            );
        public String Test
            {
                get { return (String)GetValue(TestProperty); }
                set { SetValue(TestProperty, value); }
            }
        public MainWindow()
        {
            InitializeComponent();
            Test = "Yip!";
        }
    }
}

UserControl1.xaml:

<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" Name="BobControl">
    <Grid>
        <Label Content="UserControl1" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="85,2,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=Test, ElementName=BobControl}" />
    </Grid>
</UserControl>

UserControl1.xaml.cs:

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

namespace WpfApplication1
{
    public partial class UserControl1 : UserControl
    {
        public static readonly DependencyProperty TestProperty = DependencyProperty.RegisterAttached
            (
                "Test",
                typeof(String),
                typeof(UserControl1),
                new FrameworkPropertyMetadata
                    (
                        null,
                        FrameworkPropertyMetadataOptions.Inherits
                    )
            );
        public String Test
            {
                get { return (String)GetValue(TestProperty); }
                set { SetValue(TestProperty, value); }
            }

        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

我无法找到实现此目的的明确示例。在MainWindow和UserControl1中使用RegisterAttached是我最好的猜测。肯定有一些我想念的东西!

更新

我希望能够在任意结构中创建我的控件,将值设置在树的顶部并使默认值向下流动(类似于DataContext的工作方式)。当TestProperty不在MainWindow和UserControl1的共同祖先类中时,这是否可行?

另外,我想避免引用源类,因为有时它会是一个Window,但在其他情况下它可能是Windows窗体中的主机控件。这可能吗?

RESOLVE

我认为我的困惑源于想要使用非附加依赖属性的语法来实现值继承。我想使用以下xaml:

<Window ... Test="Fred" />

使用以下语法访问UserControl中的继承值:

string Value = this.Test;

但是,根据Microsoft的Property Value Inheritance页面,如果您希望继承属性值,则必须通过附加属性。

如果上面的代码被正确重写(使用静态getter / setter方法声明属性一次),那么我的xaml将如下所示:

<Window ... my:MainWindow.Test="Fred" />

我在UserControl中的代码看起来像这样:

string Value = MainWindow.GetTest( this );

2 个答案:

答案 0 :(得分:1)

你在这里犯的错误是两次申报财产。只需在MainWindow中声明它,而不是在UserControl1中声明它。然后在MainWindow中声明静态getter和setter方法:

public static string GetTest(DependencyObject obj)
{
    return (String)obj.GetValue(TestProperty);       
}

public static void SetTest(DependencyObject obj, string value)
{
    obj.SetValue(TestProperty, value);
}

在此处获取有关custom attached properties

的更多信息

现在,当UserControl1位于MainWindow的元素树中的某个位置时,尝试在初始化后使用UserControl1执行以下操作:

UserControl1 uc = this; // for example in a UserControl1 event handler
string test = MainWindow.GetTest(uc);

编辑:您也可以在UserControl1或任何其他类中定义属性,并且由于它是附加属性,因此该类甚至不必从DependencyObject派生。

答案 1 :(得分:1)

您似乎可能误解了继承的含义。如果在控件上设置依赖项属性,则该属性的值在其内部的控件中将是相同的。您不需要重新声明属性本身(这只会创建另一个完全不同的属性)。

继承的一个例子:

<Window ...
        xmlns:local="..."
        local:MainWindow.Test="Lorem Ipsum">
    <Button Name="button"/>

在代码中,您应该能够获得按钮上的值,它应该与窗口上的值相同。

var test = (string)button.GetValue(MainWindow.TestProperty);
// test should be "Lorem Ipsum".