In silverlight, I can not get INotifyPropertyChanged to work like I want it to when binding to a dictionary. In the example below, the page binds to the dictionary okay but when I change the content of one of the textboxes the CustomProperties property setter is not called. The CustomProperties property setter is only called when CustomProperties is set and not when the values within it are set. I am trying to do some validation on the dictionary values and so am looking to run some code when each value within the dictionary is changed. Is there anything I can do here?
C#
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
MyEntity ent = new MyEntity();
ent.CustomProperties.Add("Title", "Mr");
ent.CustomProperties.Add("FirstName", "John");
ent.CustomProperties.Add("Name", "Smith");
this.DataContext = ent;
}
}
public class MyEntity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler System.ComponentModel.INotifyPropertyChanged.PropertyChanged;
public delegate void PropertyChangedEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e);
private Dictionary<string, object> _customProps;
public Dictionary<string, object> CustomProperties {
get {
if (_customProps == null) {
_customProps = new Dictionary<string, object>();
}
return _customProps;
}
set {
_customProps = value;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("CustomProperties"));
}
}
}
}
VB
Partial Public Class MainPage
Inherits UserControl
Public Sub New()
InitializeComponent()
Dim ent As New MyEntity
ent.CustomProperties.Add("Title", "Mr")
ent.CustomProperties.Add("FirstName", "John")
ent.CustomProperties.Add("Name", "Smith")
Me.DataContext = ent
End Sub
End Class
Public Class MyEntity
Implements INotifyPropertyChanged
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
Private _customProps As Dictionary(Of String, Object)
Public Property CustomProperties As Dictionary(Of String, Object)
Get
If _customProps Is Nothing Then
_customProps = New Dictionary(Of String, Object)
End If
Return _customProps
End Get
Set(ByVal value As Dictionary(Of String, Object))
_customProps = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("CustomProperties"))
End Set
End Property
End Class
Xaml
<TextBox Height="23" Name="TextBox1" Text="{Binding Path=CustomProperties[Title], Mode=TwoWay}" />
<TextBox Height="23" Name="TextBox2" Text="{Binding Path=CustomProperties[FirstName], Mode=TwoWay}" />
<TextBox Height="23" Name="TextBox3" Text="{Binding Path=CustomProperties[Name], Mode=TwoWay}" />
Here is a one (somewhat oversimplified) solution.
public class MyEntity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private readonly Dictionary<string, object> _customProps = new Dictionary<string, object>();
public void AddCustomProperty(string key, object value)
{
_customProps.Add(key, value);
}
public object this[string key]
{
get { return _customProps[key]; }
set
{
// The validation code of which you speak here.
_customProps[key] = value;
NotifyPropertyChanged("Item[" + key "]");
}
}
private void NotifyPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
MainPage:-
public MainPage()
{
InitializeComponent();
MyEntity ent = new MyEntity();
ent.AddCustomProperty("Title", "Mr");
ent.AddCustomProperty("FirstName", "John");
ent.AddCustomProperty("Name", "Smith");
this.DataContext = ent;
}
MainPage Xaml:-
<TextBox Height="23" Name="TextBox1" Text="{Binding [Title], Mode=TwoWay}" />
<TextBox Height="23" Name="TextBox2" Text="{Binding [FirstName], Mode=TwoWay}" />
<TextBox Height="23" Name="TextBox3" Text="{Binding [Name], Mode=TwoWay}" />
The important thing for your issue is that your code is involved in the assigning the property value into the dictionary. Originaly your code exposed the Dictionary
, all the assignment work went through framework component code. In this version MyEntity
has a string indexer where the custom properties are assigned directly and the Dictionary
is made private.
Note the implementation of INotifyPropertyChanged
is not strictly necessary to answer your specific question but I suspect you will need it. If for example you re-assign a new value to a custom property you would want the UI to be notified.
A collection needs to implement the INotifyCollectionChanged interface in addition to the INotifyPropertyChanged interface to support data binding. The ObservableCollection class implements them for a List-like collection, but I believe there is no dictionary-like collection in the .NET Framework that does this. You likely have to implement it yourself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With