Lokalisierte Model Entity Wpf

  • C#
  • .NET 4.5

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von Radinator.

    Lokalisierte Model Entity Wpf

    Hi, sitz gerade an meinem ersten größern Projekt und stehe gerade vor der herrausforderung das Programm zu lokalisieren, kein Problem soweit, nur muss ich jetzt auch schauen das die Daten die ich bekomme (Werden beim 1. Programm Start aus einer Drittanwender DLL geladen und per Entity Framework (Code First) persistiert), jetzt stellt sich mir die Frage wie ich das am besten angehe das die Daten on-the-fly übersetzt [*] werden, mein erster Ansatz war das ich der Klasse einfach eine Property für jede Sprache verpasse und dann je nach eingestellter Sprache an die jeweilige Property binde.

    Ist das vorgehen richtig oder ein kompletter Holzweg?

    * Die Daten liegen in der DLL in allen benötigten Sprachen vor !
    Ich denke du gehst das falsch an.
    Ich würde das mit (ich glaub so nennt man das) Fluid Interfaces machen. Auf der BASTA! hat da 2014 da Thomas Claudius Huber einen Vortrag zu Async/Await mit Fluid Interfaces gemacht.
    Was für dich wichtig ist, ist IMHO eigentlich nur der Teil ab Minute 11.

    Ich hab dir hier mal schnell was hingezaubert, mit dem du das ganze mal testen kannst:

    C#-Quellcode

    1. // BaseViewModel als Basisklasse, damit INPC nicht immer wieder neu implementiert werden muss
    2. public class BaseViewModel : INotifyPropertyChanged
    3. {
    4. public event PropertyChangedEventHandler PropertyChanged;
    5. protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    6. {
    7. var handler = PropertyChanged;
    8. if (handler != null)
    9. {
    10. handler(this, new PropertyChangedEventArgs(propertyName));
    11. }
    12. }
    13. }

    C#-Quellcode

    1. // Das MainViewModel, welches in der Anzeige verwendet wird
    2. public class MainViewModel : BaseViewModel
    3. {
    4. private ILocalisationProvider localisationProvider;
    5. private DisplayData displayData;
    6. // ctor mit Dependency Inversion (Auslagerung der Abhängigkeit nach außen
    7. // -> Der Aufrufer/Ersteller entscheidet, WELCHE Sprache verwendet werden soll)
    8. // SOLID Prinzip
    9. public MainViewModel(ILocalisationProvider localisationProvider)
    10. {
    11. this.localisationProvider = localisationProvider;
    12. }
    13. // Kann entweder direkt oder über ein ICommand aufgerufen werden
    14. private void LoadData()
    15. {
    16. // Läd die (lokalisierten) Daten in die private Variable
    17. this.displayData = this.localisationProvider.GetLocalDisplayData();
    18. // Anschließende Übertragung der Daten aus this.displayData auf die Properties
    19. // Zur Anzeige im View
    20. this.Text = this.displayData.Text
    21. }
    22. private string text;
    23. public string Text
    24. {
    25. get { return this.text; }
    26. set
    27. {
    28. this.text = value;
    29. OnPropertyChanged();
    30. }
    31. }
    32. }

    C#-Quellcode

    1. // Das Interface, welches die Dependency Inversion erfüllt
    2. public interface ILocalisationProvider
    3. {
    4. IDisplayData GetLocalDisplayData();
    5. }

    C#-Quellcode

    1. // Die Klasse, welche die Daten trägt, die auf dem View dargestellt werden (sollen)
    2. // = das "Model(l)"
    3. public class DisplayData
    4. {
    5. public string Text { get; set; }
    6. }

    C#-Quellcode

    1. // Für die deutsch-sprachige Ausgabe
    2. public class GermanLocalisationProvider : ILocalisationProvider
    3. {
    4. public DisplayData GetLocalDisplayData()
    5. {
    6. return new DisplayData()
    7. {
    8. Text = "Hallo Welt!"
    9. };
    10. }
    11. }
    12. // Für die englisch-sprachige Ausgabe
    13. public class EnglishLocalisationProvider : ILocalisationProvider
    14. {
    15. public DisplayData GetLocalDisplayData()
    16. {
    17. return new DisplayData()
    18. {
    19. Text = "Hello World!"
    20. };
    21. }
    22. }

    C#-Quellcode

    1. // Und hier der Aufruf aus dem Code Behind View
    2. public partial class MainWindow : Window
    3. {
    4. MainViewModel mvm;
    5. ILocalisationProvider germanLocalisation;
    6. ILocalisationProvider englishLocalisation;
    7. public MainWindow()
    8. {
    9. InitializeComponent();
    10. this.germanLocalisation = new GermanLocalisationProvider();
    11. this.englishLocalisation = new EnglishLocalisationProvider();
    12. this.mvm = new MainViewModel(this.englishLocalisation);
    13. this.rootElement.DataContext = this.mvm;
    14. }
    15. //Es kann eine welchselnde Auswahl über RadioButtons getroffen werden.
    16. private void cbGermanLocal_Checked(object sender, RoutedEventArgs e)
    17. {
    18. this.mvm = new MainViewModel(this.germanLocalisation);
    19. this.rootElement.DataContext = this.mvm;
    20. }
    21. private void cbEnglishLocal_Checked(object sender, RoutedEventArgs e)
    22. {
    23. this.mvm = new MainViewModel(this.englishLocalisation);
    24. this.rootElement.DataContext = this.mvm;
    25. }
    26. }


    Wenn du noch Fragen hast, stehe ich dir gerne (auch per PN) zur Verfügung
    Lg Radinator
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell
    Das sieht schon einmal sehr interessant aus, nur mein Problem ist das ich die Daten in Form einer List<ComboItem> bekomme, ComboItem :

    C#-Quellcode

    1. public class ComboItem
    2. {
    3. public string Text { get; set; }
    4. public int Value { get; set; }
    5. }


    Welche in zwangsweise persistieren muss (die externe dll soll ausgetauscht werden können, was einem Datenupdate entsprechen würde).
    Das nächste Problem ist das ich eine strikte Trennung von Daten und GUI beibehalten möchte deshalb hole ich mir die Daten bisher einmalig bei der Initialisierung des Moduls mithilfe des Unit of Work Pattern. (Die Daten müssen allen neuen (Von dritten entwickelten) möglichen Modulen zur Verfügung stehen)

    //Edit: Leider habee ich im Moment kein richtiges Internet zur Hand und kann mir deshalb das Video nicht anschauen :)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Majomi“ ()

    Majomi schrieb:

    Leider habee ich im Moment kein richtiges Internet zur Hand und kann mir deshalb das Video nicht anschauen
    Wenn du den Code von mir verstanden hast, dann brauchst du dir das Video eigentlich nicht ansehen

    Majomi schrieb:

    Das sieht schon einmal sehr interessant aus
    Danke :D

    Majomi schrieb:

    nur mein Problem ist das ich die Daten in Form einer List<ComboItem> bekomme
    Ich seh da jetzt kein Problem. Dann tausch doch einfach meine DisplayData Property durch dein List<ComboItem> aus. Dann liefert hatl der Provider kein DisplayData sondern deine List<ComboItem>.

    Majomi schrieb:

    Welche in zwangsweise persistieren muss
    Heißt für mich, die Daten irgendwo als Datei auf dem FileSystem (also XML/CSV/Text/...) abspeichern. Was hat das mit Austausch der DLL zu tun?

    Majomi schrieb:

    Das nächste Problem ist das ich eine strikte Trennung von Daten und GUI beibehalten möchte
    Wie vestößt dein Ansatz der Trennung zwischen Code und GUI gegen meinen Vorschlag?
    Gegen diesen Grunsatz verstoßen würdest du/ würde man, wenn man etwa Elemente direkt dem ListControl aus dem Codebehind hinzufügt

    C#-Quellcode

    1. // MainViewModel im Konstruktor
    2. this.listbox.Items.Add(new ComboItem() { "Text1", 1})
    3. this.listbox.Items.Add(new ComboItem() { "Text2", 3})
    4. this.listbox.Items.Add(new ComboItem() { "Text3", 3})


    Edit: Trennung von GUI und Code heßt nur, dass du im Codebehind nicht in deinen Controls herumpfuschen sollst (also den Inhalt änderst). IMHO spricht nix dagegen während des Programm Ablaufes die Daten nochmals/mehrmals zu laden und sie halt dann über WPF DataBinding wieder ans View zu bringen.
    Bsp: Was würdest du denn bisher bitte machen, wenn jemand während des Programmablaufes die Sprache ändern will (weil sie bisher auf Chinesisch eingestellt war und der Benutzer kein Chinesisch vesteht)?

    Lg Radinator


    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Radinator“ ()