1

我正在尝试利用从窗口到用户控件的属性值继承。据我了解,您可以通过声明附加的 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!";
        }
    }
}

用户控件1.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 的共同祖先类中时,这可能吗?

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

解决

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

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

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

string Value = this.Test;

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

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

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

我在 UserControl 中的代码如下所示:

string Value = MainWindow.GetTest( this );
4

2 回答 2

2

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

继承示例:

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

然后在代码中,您应该能够获取按钮上的值,并且它应该与窗口上的值相同。

var test = (string)button.GetValue(MainWindow.TestProperty);
// test should be "Lorem Ipsum".
于 2012-04-10T14:29:56.280 回答
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);
}

在此处获取有关自定义附加属性的更多信息。

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

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

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

于 2012-04-10T14:28:45.467 回答