Reputation: 3025
I have this very small test app that explores object binding in WPF. I am binding to instances of this class MyData { public string Info { get; set; } }
local class.
I am exploring binding to a local object in xaml, setting data context at runtime and modifying resource instances at runtime.
I am using both window and application resources to see their impact, as defined below:
App.xaml resources
<local:MyData x:Key="myAppData" Info="App resource information" />
<local:MyData x:Key="myAppEmptyData" />
<local:MyData x:Key="myAppBogusData" Info="-" />
Window.xaml resources
<local:MyData x:Key="myWindowData" Info="Window resource information" />
<local:MyData x:Key="myWindowEmptyData" />
The my[App|Window]EmptyData have a null Info member, and I am trying to modify it at runtime. I am doing this on window load:
(this.Resources["myWindowEmptyData"] as MyData).Info = "window resource info set on runtime";
(Application.Current.Resources["myAppEmptyData"] as MyData).Info = "app resource info set on runtime";
(Application.Current.Resources["myAppBogusData"] as MyData).Info = "app resource info set on runtime";
this.lblDataContextSetAtRuntime.DataContext = new MyData() { Info = "data context set at runtime" };
The code for the main window below. Green labels are expected behavior. Blue labels represent unmodified resources that one expects not to get modified (static + window). Red labels are unexpected behavior. See inline comments too.
MainWindow.xaml
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
DataContext="{StaticResource myWindowData}">
<Grid.RowDefinitions>
<RowDefinition Height="1*" /><RowDefinition Height="1*" /><RowDefinition Height="1*" /><RowDefinition Height="1*" /><RowDefinition Height="1*" /><RowDefinition Height="1*" /><RowDefinition Height="1*" /><RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!--this uses data context from the grid-->
<Label Content="{Binding Path=Info}" Background="Green" Grid.Row="0" />
<!--normal to not be updateable since window resources-->
<Label DataContext="{StaticResource myWindowEmptyData}" Content="{Binding Path=Info}" Background="CadetBlue" Grid.Row="1" x:Name="lblStaticWindowResource" />
<Label DataContext="{DynamicResource myWindowEmptyData}" Content="{Binding Path=Info}" Background="CadetBlue" Grid.Row="2" x:Name="lblDynamicWindowResource" />
<!--data context set at runtime-->
<Label Content="{Binding Path=Info}" Grid.Row="3" Background="Green" x:Name="lblDataContextSetAtRuntime" />
<!--uses data context from app-->
<Label DataContext="{StaticResource myAppData}" Content="{Binding Path=Info}" Background="Green" Grid.Row="4" x:Name="lblAppData" />
<!--static app resource not modifiable-->
<Label DataContext="{StaticResource myAppEmptyData}" Content="{Binding Path=Info}" Background="CadetBlue" Grid.Row="5" x:Name="lblStaticAppResource"/>
<!--DYNAMIC APP RESOURCE SHOULD GET MODIFIED-->
<Label DataContext="{DynamicResource myAppEmptyData}" Content="{Binding Path=Info}" Background="Red" Grid.Row="6" x:Name="lblDynamicEmptyAppResource" />
<Label DataContext="{DynamicResource myAppBogusData}" Content="{Binding Path=Info}" Background="Red" Grid.Row="7" x:Name="lblDynamicBogusAppResource" />
</Grid>
Even though in the debugger window one notices the resources are modified
, at runtime there's no content for the blue and red labels. I thought there was an issue with the resources with null property, bit not even myAppBogusData gets updated.
Upvotes: 0
Views: 1387
Reputation: 25211
MyData
must implement INotifyPropertyChanged
in order for the Info
property to update via binding.
class MyData : INotifyPropertyChanged
{
private string info;
public string Info
{
get { return info; }
set
{
if (info != value)
{
info = value;
RaisePropertyChanged("Info");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Other than that, you don't have to use a DynamicResource
- a StaticResource
would suffice. You would only need to use a DynamicResource
if you have a need to change the MyData
instance entirely. For example:
Application.Current.Resources["myAppBogusData"] = new MyData() { Info = "New data" };
If you're just changing properties on a given instance, you can use StaticResource
.
Upvotes: 1