1
votes

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

        }


    }
}
2
It may be worth pointing out that this isn't a great strategy for WPF localization. It is far more common and useful to use resources for your localized strings rather than storing them in a Dictionary. There is an article on CodeProject (codeproject.com/KB/WPF/WPFLocalize.aspx) which shows a nice way to change the language of the resource file at runtime. - Martin Harris

2 Answers

2
votes

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)

1
votes

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.