tags:

views:

286

answers:

2

In the following code example, you can move the slider from German to English and see that text block get translated at runtime, however:

  • only the TextBlock bound to a string gets updated
  • the TextBlock bound to a Dictionary does not get updated

It seems that the View simply gets the Dictionary object once and then doesn't update anymore. I tried Mode=TwoWay but that has no effect.

What do I have to do so that elements bound to objects get updated via binding?

View:

<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");
            }

        }


    }
}
+1  A: 

You need to use an ObservableCollection<> instead.

The WPF binder must be notified when changed have occurred, you are calling OnPropertyChanged when the dictionary property is set, but you also need some why of notifying the binder that values inside the dictionary have changed. An ObservableCollection<> will do this for you. It raises events when items are added/removed from the collection.

Simon P Stevens
I could implement Observable collection instead of dictionary, but then how do I pull an object out of the observable collection with a key as in "Binding Translations[add]" since I want to bind objects in the collection to e.g. TextBlock instead of e.g. ListView.
Edward Tanguay
I want to be able to do this: <TextBlock Text="{Binding Translations[obsColl.key[add]]}" />, the reason being that I have 100s of strings in my Translation object and I don't want to make 100s of ViewModelProperties to read them all, so I need an ObservableCollection that I can access with key values, e.g. an "ObservableDictionary"
Edward Tanguay
Just create your own ObservableDictionary<> class. implement the interfaces for IDictionary<<> INotifyCollectionChanged and INotifyPropertyChanged. Implement the add, remove methods and call the collection/property changed events at the appropriate times. Use a private normal Dictionary<> or KeyedCollection<> internally within your class to store the data. I think Martin gave a good link on how to get started on doing this.
Simon P Stevens
+2  A: 

You need the equivalent of an ObservableList but for a Dictionary. There isn't one by default in the Framework, but an article describing one way to write one can be found here.

The reason that your code doesn't work as it stands now is because you fire the NotifyPropertyChanged event in the setter of the Translations Dictionary, but since your FillTranslations method doesn't create a new Dictionary the setter doesn't get called and the event doesn't fire. I suppose you could sidestep the ObservableDictionary class if you created a new dictionary and assigned it which in turn would trigger the event and rebind the entire list, but in the long run it is more efficient to keep the same dictionary instance and notify the control that the collection has changed through the Observable pattern (implementing INotifyCollectionChanged on the dictionary)

Martin Harris