Reputation: 4351
I'm trying to take advantage of Property Value Inheritance from a Window to a UserControl. As far as I understand, you can achieve this by declaring an attached DependencyProperty (in conjunction with the FrameworkPropertyMetadataOptions.Inherits option).
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();
}
}
}
I haven't been able to find an explicit example to achieve this. The use of RegisterAttached in MainWindow and UserControl1 is my best guess. There must be something I'm missing!
UPDATE
I'd like to be able to create my controls in an arbitrary structure, set the value at the top of the tree and have the default value trickle down (similar to how DataContext works). Is this possible when TestProperty isn't in a common ancestor class for MainWindow and UserControl1?
Also, I want to avoid referencing the source class, since sometimes it will be a Window but in other cases it might be the host control in Windows Forms. Is this possible?
RESOLVE
I think my confusion stemmed from wanting to use the syntax of a non-attached dependency property to achieve value inheritance. I wanted to use the following xaml:
<Window ... Test="Fred" />
And access the inherited value in UserControl with the following syntax:
string Value = this.Test;
However, according Microsoft's Property Value Inheritance page, if you wish to inherit property values, then it must be through an attached property.
If above the code was re-written properly (declare the property once, with static getter/setter methods) then my xaml would look like this:
<Window ... my:MainWindow.Test="Fred" />
And my code behind in UserControl would look like this:
string Value = MainWindow.GetTest( this );
Upvotes: 1
Views: 2508
Reputation: 128098
The mistake you made here is to declare the property twice. Just declare it in MainWindow, not also in UserControl1. Then declare static getter and setter methods like this in MainWindow:
public static string GetTest(DependencyObject obj)
{
return (String)obj.GetValue(TestProperty);
}
public static void SetTest(DependencyObject obj, string value)
{
obj.SetValue(TestProperty, value);
}
Get more info here about custom attached properties.
Now when a UserControl1 is somewhere in the element tree in MainWindow, try to do something like the following with UserControl1 after it has been initialized:
UserControl1 uc = this; // for example in a UserControl1 event handler
string test = MainWindow.GetTest(uc);
EDIT: You could as well define the property in UserControl1 or in any other class, and since it is an attached property, that class does not even have to be derived from DependencyObject.
Upvotes: 1
Reputation: 185210
It seems that you might be misunderstanding what value inheritance means. If you set a dependency property on a control the value of that property will be the same in the controls inside of it. You don't need to redeclare the property itself (that just creates another property that is completely distinct).
An example of inheritance:
<Window ...
xmlns:local="..."
local:MainWindow.Test="Lorem Ipsum">
<Button Name="button"/>
In code you then should be able to get the value on the button and it should be the same as on the window.
var test = (string)button.GetValue(MainWindow.TestProperty);
// test should be "Lorem Ipsum".
Upvotes: 2