WPF RaisePropertyChanged triggert Converter nicht, wenn an eine DependencyProperty gebunden wird.

  • WPF
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    WPF RaisePropertyChanged triggert Converter nicht, wenn an eine DependencyProperty gebunden wird.

    Kurz zur Ausgangslage:
    Ich habe in meinem Projekt eine statische MultiLanguage-Klasse.
    Spoiler anzeigen

    C#-Quellcode

    1. public static class MultiLanguage
    2. {
    3. public enum Languages { German, English }
    4. public static event EventHandler<Languages> LanguageChanged;
    5. public static Languages Language
    6. {
    7. get => _language;
    8. set
    9. {
    10. if (_language != value)
    11. {
    12. _language = value;
    13. LanguageChanged?.Invoke(null, _language);
    14. }
    15. }
    16. }
    17. private static Languages _language;
    18. }


    Die Klasse hat eine Property Language, welche die aktuell gewählte Sprache beinhaltet. Ändert sich die Sprache, wird ein Event LanguageChanged gefeuert.
    In der GUI soll nun das Event abonniert werden und je nach Sprache die Texte angepasst werden. In der richtigen Anwendung ist das mit einem ResourceManager realisiert, welcher dann je nach Sprache in einer entsprechenden .resx-Datei Einträge auswählt.
    Ich habe meine UI-Elemente an diverse Properties gebunden und teilweise einen Converter für die MultiLanguage-Thematik verwendet.
    Spoiler anzeigen

    C#-Quellcode

    1. public sealed class MeinConverter : IValueConverter
    2. {
    3. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    4. {
    5. if (value?.GetType() != typeof(int))
    6. return null;
    7. switch (MultiLanguage.Language)
    8. {
    9. case MultiLanguage.Languages.German:
    10. return "deutscher wert";
    11. case MultiLanguage.Languages.English:
    12. return "english value";
    13. default:
    14. return "ungültige sprache";
    15. }
    16. }
    17. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    18. {
    19. throw new NotImplementedException();
    20. }
    21. }


    Das funktioniert auch alles soweit...jetzt bin ich allerdings auf ein komisches Verhalten gestoßen.
    Wenn von einem TextBlock die Text-Property an eine DependencyProperty in meinem Control gebunden ist und ich bei gefeuertem LanguageChanged-Event RaisePropertyChanged() aufrufe, komme ich nicht in meinen verwendeten Converter rein. Bei "normalen" Properties funktioniert das aber nach wie vor tadellos.

    Abonnieren des LanguageChanged-Events im Control:

    C#-Quellcode

    1. MultiLanguage.LanguageChanged += (s, e) => RaisePropertyChanged(null);


    Properties im Control/Window:

    C#-Quellcode

    1. public static readonly DependencyProperty NumbersDPProperty =
    2. DependencyProperty.Register(nameof(NumbersDP), typeof(ObservableCollection<int>), typeof(MainWindow), new PropertyMetadata(new ObservableCollection<int>()));
    3. public ObservableCollection<int> NumbersDP { get => (ObservableCollection<int>)GetValue(NumbersDPProperty); set => SetValue(NumbersDPProperty, value); }
    4. public ObservableCollection<int> NumbersNormal { get; } = new ObservableCollection<int>();


    Und Binding im UI:

    XML-Quellcode

    1. <TextBlock Text="{Binding NumbersDP.Count, Converter={StaticResource MeinConverter}, StringFormat='{}DP: {0}'}" />
    2. <TextBlock Text="{Binding NumbersNormal.Count, Converter={StaticResource MeinConverter}, StringFormat='{}Normal: {0}'}" />


    Im Anhang hab ich das ganze nochmal beispielhaft als Solution.

    Als "Lösung" habe ich bis jetzt im Netz nur gefunden, im XAML dem entsprechenden Control einen Namen mit z.B. x:Name="TxtDP" geben und dann im Code-Behind TxtDP.GetBindingExpression(TextBlock.TextProperty).UpdateTarget(); aufrufen, wenn LanguageChanged gefeuert wurde.
    Das finde ich aber irgendwie nicht so geil muss ich sagen, gibt's da noch andere Lösungen oder mach ich was falsch?
    Danke für eure Hilfe.
    Dateien
    • TestDP.zip

      (43,19 kB, 52 mal heruntergeladen, zuletzt: )
    Dumm ist der, der dumm ist. Nicht andersrum!

    Schmittmuthelm schrieb:

    Abonnieren des LanguageChanged-Events im Control:
    C#-Quellcode
    MultiLanguage.LanguageChanged += (s, e) => RaisePropertyChanged(null);
    Das sieht mir abwegig aus.
    Ein Control sollte kein PropertyChanged feuern.
    Und ein PropertyChanged (was hier ja garnet zu feuern wäre) sollte immmer auch die Property angeben, auf die es sich bezieht (aber wie gesagt: hier ja nicht).

    Das nur ganz generell.



    Was anderes generelles: Ich würde die Sprache bereits im Viewmodel bereitstellen - nicht erst im Gui zusammenbasteln.



    Und nochwas:
    machmal einen Haltepunkt in
    public ObservableCollection<int> NumbersNormal { get; } = new ObservableCollection<int>();, und prüfe, ob da bei jedem Abruf der Property nicht vielleicht eine neue OC erzeugt wird.
    Das wäre ja vermutlich nicht gut.



    ach, zu deiner Frage: Nee - ich sehe hier auch keinen Anlass, da iwas komisches im CodeBehind zu veranstalten.
    Wie gesagt: Mein Ansatz wäre ja eh, die Sprachlichkeit im ViewModel abzuhanden.

    ErfinderDesRades schrieb:

    sollte immmer auch die Property angeben

    RaisePropertyChanged(null) hier ja nur exemplarisch, um das PropertyChanged für alle Properties auszulösen.

    ErfinderDesRades schrieb:

    und prüfe, ob da bei jedem Abruf der Property nicht vielleicht eine neue OC erzeugt wird.

    Wird nur einmalig erzeugt. Anders wäre es bei public ObservableCollection<int> NumbersNormal { get => new ObservableCollection<int>(); }


    Die generellen Einwände mal außen vor gelassen, wieso verhalten sich hier normale Properties und DependencyProperties anders?
    Dumm ist der, der dumm ist. Nicht andersrum!

    Schmittmuthelm schrieb:

    RaisePropertyChanged(null) hier ja nur exemplarisch, um das PropertyChanged für alle Properties auszulösen.
    Exemplarisch falsch.
    Ein Control sollte kein PropertyChanged feuern.



    Schmittmuthelm schrieb:

    Die generellen Einwände mal außen vor gelassen, wieso verhalten sich hier normale Properties und DependencyProperties anders?
    Sind halt verschiedene Dinge, deshalb verhalten sie sich anders.
    Das Wpf-Konzept sieht vor, dass im Viewmodel Properties INotifyPropertyChanged implementieren, und somit das PropertyChanged-Event feuern.

    Controls hingegen implementieren nix dergleichen, sondern haben diese komischen DependencyProperties - (ich seh grade, du hast deine da ausserdem ganz falsch implementiert.)
    Jedenfalls das Wpf-Konzept sieht vor, dass Viewmodel (INotifyPropertyChanged) gebaut werden, und dann an Control-Properties gebunden werden, und die Control-Properties sind als DependencyProperties auszuführen.
    Im Xaml soll man dann Bindings setzen zwischen (richtig implementierten) Control-(Dependency)Properties und Viewmodel-Properties.

    Tatsächlich braucht man Control-Properties so gut wie nie, sondern die bereits vorhandenen sind meist vollkommen ausreichend.

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