2010-04-14 4 views
4

Dans Silverlight, je ne parviens pas à ce que INotifyPropertyChanged fonctionne comme je le souhaite lors de la liaison à un dictionnaire. Dans l'exemple ci-dessous, la page se lie bien au dictionnaire, mais lorsque je modifie le contenu de l'une des zones de texte, l'accesseur de propriété CustomProperties n'est pas appelé. Le paramètre de propriété CustomProperties est uniquement appelé lorsque CustomProperties est défini et non lorsque les valeurs qu'il contient sont définies. J'essaye de faire une certaine validation sur les valeurs du dictionnaire et je cherche donc à exécuter du code quand chaque valeur dans le dictionnaire est changée. Y a-t-il quelque chose que je puisse faire ici?Liaison à un dictionnaire dans Silverlight avec INotifyPropertyChanged

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}" /> 

Répondre

6

Une collection doit mettre en œuvre la INotifyCollectionChanged interface en plus de la INotifyPropertyChanged interface pour supporter de liaison de données. Le ObservableCollection class les implémente pour une collection semblable à une liste, mais je crois qu'il n'y a pas de collection de type dictionnaire dans le .NET Framework qui le fait. Vous devez probablement l'implémenter vous-même.

+0

Merci, j'ai twitté la mise en œuvre de l'ObservatoireDictionnaire de dr wpf: http://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/ –

8

Voici une solution (un peu trop simplifiée).

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}" /> 

L'important pour votre problème est que votre code est impliqué dans l'attribution de la valeur de la propriété dans le dictionnaire. Originaly votre code a exposé le Dictionary, tout le travail d'attribution est passé par le code de composant de cadre. Dans cette version MyEntity a un indexeur de chaîne où les propriétés personnalisées sont assignées directement et le Dictionary est rendu privé.

Notez que l'implémentation de INotifyPropertyChanged n'est pas strictement nécessaire pour répondre à votre question spécifique mais je suppose que vous en aurez besoin. Si, par exemple, vous réaffectez une nouvelle valeur à une propriété personnalisée, vous souhaitez que l'interface utilisateur soit notifiée.

Questions connexes