How would one propogate changes to properties of the DataContext
in the designer to the actual datacontext object? Is that possible?
Here is what I tried - I convert the DataContext to a local value in XML - thinking any changes I make to it in the designer would be reflected on the DataContext object.
This is the SSCCE. I have a UserControl called MammalUC and a class called Kangaroo. I use the object of the class Kangaroo as the DataContext. The below code shows that.
using System.ComponentModel;
using System.Windows.Controls;
namespace WPFTestABC
{
/// <summary>
/// User Control : Interaction logic for MammalUC.xaml
/// </summary>
public partial class MammalUC : UserControl
{
public MammalUC()
{
InitializeComponent();
Kang = new Kangaroo();
this.DataContext = Kang;
}
private Kangaroo kang;
/// <summary>
/// This is the datacontext.
/// </summary>
[Category("ForDebug")]
[TypeConverter(typeof(ExpandableObjectConverter))]
public Kangaroo Kang
{
get{ return kang;}
set {kang = value;}
}
}
/// <summary>
/// Kangaroo class.
/// </summary>
public class Kangaroo : INotifyPropertyChanged
{
private int age;
public int Age
{
get { return age; }
set
{
age = value;
OnPropertyChanged("Age");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
I bind the Age property to the UserControl like this -
<UserControl x:Class="WPFTestABC.MammalUC"
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"
xmlns:local="clr-namespace:WPFTestABC"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox Text="{Binding Age}" Background="#FFD88787"></TextBox>
</Grid>
</UserControl>
I then place the MammalUC on to a window. Then convert the Kang object to a local value (I've tried as a Static Resource also). In the designer property grid I change the value, but I don`t see the value being updated.
<Window x:Class="WPFTestABC.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFTestABC"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<!--<Window.Resources>
<local:Kangaroo x:Key="Kangaroo1" Age="65"/>
</Window.Resources>-->
<Grid>
<!--Using Static Resource -->
<local:MammalUC HorizontalAlignment="Left" Height="100" Margin="210,115,0,0" VerticalAlignment="Top" Width="100">
<!--Converting to local resource-->
<local:MammalUC.Kang>
<local:Kangaroo Age="85"/> <!--Value never updates-->
</local:MammalUC.Kang>
</local:MammalUC>
</Grid>
</Window>
Then convert the Kang object to a local value
I don't have a good guess about what you're trying to say there. I don't see any object being converted to anything, and I don't know what you mean by "local value". I don't know what you think you're doing.
But here's what you are doing:
<!--Using Static Resource -->
<local:MammalUC HorizontalAlignment="Left" Height="100" Margin="210,115,0,0" VerticalAlignment="Top" Width="100">
<!--Converting to local resource-->
<local:MammalUC.Kang>
<local:Kangaroo Age="85"/> <!--Value never updates-->
</local:MammalUC.Kang>
</local:MammalUC>
There is no "static resource" in this XAML and no "local resource". You should find out what the word "resource" means in WPF.
What you are doing is replacing the Kang
property's existing value with a new instance of the Kangaroo
class.
Why doesn't that work? Here's why:
private Kangaroo kang;
/// <summary>
/// This only becomes the datacontext if you explicitly assign it
/// to this.DataContext.
/// </summary>
[Category("ForDebug")]
[TypeConverter(typeof(ExpandableObjectConverter))]
public Kangaroo Kang
{
get{ return kang;}
set {kang = value;}
}
You never told anybody you changed it. You aren't updating the data context. Back in the constructor, you set the DataContext
to the value that Kang
had at that moment in time. What happens when you give Kang
a new value? Nothing much. It sets private kang
, and that's it. Of course it doesn't update the DataContext
; you never told it to.
The Age
property of Kangaroo
raises PropertyChanged
when it changes, so that works. There's nothing comparable happening with Kang
. Now, controls don't use INotifyPropertyChanged
; they use dependency properties. Dependency properties also raise notification events when they change, but you can also put bindings on them in XAML, so they're more suitable for controls.
You could add a new dependency property of type Kangaroo
and have it update the DataContext
, but there's a simpler way to do that.
Here's what you could do to fix this problem: Get rid of private Kangaroo kang;
and change the property as follows.
public Kangaroo Kang
{
get { return (Kangaroo)DataContext; }
set { DataContext = value;}
}
public MammalUC()
{
InitializeComponent();
// This sets the DataContext.
Kang = new Kangaroo();
}
DataContext
is a dependency property. Set it, and notifications will fly behind the scenes. Things will happen.
You can't make Kang
the target of a binding. For that, you'll have to go and make it a dependency property:
#region Kang Property
public Kangaroo Kang
{
get { return (Kangaroo)GetValue(KangProperty); }
set { SetValue(KangProperty, value); }
}
public static readonly DependencyProperty KangProperty =
DependencyProperty.Register(nameof(Kang), typeof(Kangaroo), typeof(MammalUC),
new PropertyMetadata(null));
#endregion Kang Property
XAML:
<UserControl
x:Class="WPFTestABC.MammalUC"
...blah blah blah...
DataContext="{Binding Kang, RelativeSource={RelativeSource Self}}"
>
Then you could give your main viewmodel a public Kangaroo SelectedKangaroo { /* INPC garble */ }
property, and bind it in your main window:
<local:MammalUC Kang="{Binding SelectedKangaroo}" />