2009-06-17 4 views
1

Dans l'exemple de code suivant, vous pouvez déplacer le curseur de l'allemand vers l'anglais et de voir ce bloc de texte se traduit à l'exécution, cependant:Pourquoi la liaison WPF met-elle à jour les chaînes mais pas les objets?

  • seul le TextBlock lié à une chaîne est mis à jour
  • la TextBlock lié à un Dictionnairen'a pas soient mis à jour

Il semble que la vue simplement obtient le Di objet ctionary une fois et puis ne met plus à jour. J'ai essayé Mode = TwoWay mais cela n'a aucun effet.

Que dois-je faire pour que les éléments liés aux objets soient mis à jour via la liaison?

Vue:

<Window x:Class="TestObjectUpdate234.Views.MainView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:c="clr-namespace:TestObjectUpdate234.Commands" 
    Title="Main Window" Height="400" Width="800"> 
    <StackPanel Margin="10"> 

     <TextBlock Text="{Binding TranslationEdit}" /> 
     <TextBlock Text="{Binding Translations[add], Mode=TwoWay}" /> 

     <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Margin="0 20 0 0"> 
      <TextBlock Text="English" Margin="0 0 5 0"/> 
      <Slider Name="TheLanguageIndexSlider" 

       Minimum="0" 
       Maximum="1" 
       IsSnapToTickEnabled="True" 
       Width="100" 
       Margin="5" 
       Value="{Binding LanguageIndex}" 
       HorizontalAlignment="Left"/> 
      <TextBlock Text="German" Margin="5 0 0 0"/> 
     </StackPanel> 

    </StackPanel> 
</Window> 

ViewModel:

using System.Collections.Generic; 

namespace TestObjectUpdate234.ViewModels 
{ 
    public class MainViewModel : ViewModelBase 
    { 

     #region ViewModelProperty: TranslationEdit 
     private string _translationEdit; 
     public string TranslationEdit 
     { 
      get 
      { 
       return _translationEdit; 
      } 

      set 
      { 
       _translationEdit = value; 
       OnPropertyChanged("TranslationEdit"); 
      } 
     } 
     #endregion 

     #region ViewModelProperty: Translations 
     private Dictionary<string, string> _translations = new Dictionary<string, string>(); 
     public Dictionary<string, string> Translations 
     { 
      get 
      { 
       return _translations; 
      } 

      set 
      { 
       _translations = value; 
       OnPropertyChanged("Translations"); 
      } 
     } 
     #endregion 

     #region ViewModelProperty: LanguageIndex 
     private int _languageIndex; 
     public int LanguageIndex 
     { 
      get 
      { 
       return _languageIndex; 
      } 

      set 
      { 
       _languageIndex = value; 
       OnPropertyChanged("LanguageIndex"); 
       FillTranslations(); 
      } 
     } 
     #endregion 

     public MainViewModel() 
     { 
      _languageIndex = 0; //english 
      FillTranslations(); 

     } 

     private void FillTranslations() 
     { 
      if (_languageIndex == 0) 
      { 
       TranslationEdit = "Edit"; 

       Translations.Clear(); 
       Translations.Add("add", "Add"); 
      } 
      else 
      { 
       TranslationEdit = "Bearbeiten"; 

       Translations.Clear(); 
       Translations.Add("add", "Hinzufügen"); 
      } 

     } 


    } 
} 
+0

Il est peut-être intéressant de souligner que ce n'est pas une bonne stratégie pour la localisation WPF. Il est beaucoup plus commun et utile d'utiliser des ressources pour vos chaînes localisées plutôt que de les stocker dans un dictionnaire. Il y a un article sur CodeProject (http://www.codeproject.com/KB/WPF/WPFLocalize.aspx) qui montre un bon moyen de changer la langue du fichier de ressources à l'exécution. –

Répondre

1

Vous devez utiliser un ObservableCollection <> à la place. Le classeur WPF doit être notifié lorsque des modifications ont eu lieu, vous appelez OnPropertyChanged lorsque la propriété dictionary est définie, mais vous devez également indiquer pourquoi le classeur a modifié les valeurs dans le dictionnaire. Un ObservableCollection <> fera cela pour vous. Il déclenche des événements lorsque des éléments sont ajoutés/supprimés de la collection.

+0

Je pourrais implémenter la collection Observable au lieu du dictionnaire, mais ensuite comment extraire un objet de la collection observable avec une clé comme dans "Binding Translations [add]" puisque je veux lier des objets dans la collection par ex. TextBlock au lieu de par ex. ListView. –

+0

Je veux être en mesure de faire ceci: , la raison étant que j'ai 100s de chaînes dans mon objet Translation et je ne veux pas faire 100s de ViewModelProperties pour les lire tous, donc j'ai besoin d'un ObservableCollection auquel je peux accéder avec la clé valeurs, par exemple un "ObservableDictionary" –

+0

Créez simplement votre propre classe ObservableDictionary <> implémentez les interfaces pour IDictionary <<> INotifyCollectionChanged et INotifyPropertyChanged Implémentez les méthodes add, remove et appelez les événements collection/property modifiés aux moments appropriés. Dictionnaire <> ou KeyedCollection <> en interne dans votre classe pour stocker les données.Je pense que Martin a donné un bon lien sur la façon de commencer à faire cela. –

2

Vous avez besoin de l'équivalent d'un ObservableList mais d'un dictionnaire. Il n'y en a pas un par défaut dans le Framework, mais un article décrivant une façon d'en écrire un peut être trouvé. here.

La raison pour laquelle votre code ne fonctionne pas tel quel est maintenant parce que vous déclenchez l'événement NotifyPropertyChanged dans le setter du dictionnaire de traductions, mais comme votre méthode FillTranslations ne crée pas de nouveau dictionnaire, le setter n'est pas appelé et l'événement ne se déclenche pas. Je suppose que vous pourriez contourner la classe ObservableDictionary si vous créiez un nouveau dictionnaire et que vous l'assigniez, ce qui à son tour déclencherait l'événement et relancerait toute la liste, mais à long terme, il est plus efficace de conserver la même instance la collection a changé via le pattern Observable (implémentation de INotifyCollectionChanged sur le dictionnaire)

Questions connexes