[WPF] ComboBox SelectedItem Text wird nicht Refreshed/Geupdatet

  • WPF

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von C-Sharp.

    [WPF] ComboBox SelectedItem Text wird nicht Refreshed/Geupdatet

    Hallo Community,

    nach längerer Zeit Pause (ne Spaß, hab mich an PowerShell ausgetobt :D ) hab ich mal wieder eine Frage.

    Ich habe eine Anwendung die Mehrsprachig sein soll. Das funktioniert auch so weit ganz gut mit .xaml und dynamischen Ressourcen...

    Jetzt habe ich eine ComboBox um die Farben (Accent/AppTheme von MahApps) zu ändern. (Ähnlich wie bei Hurricane).

    Um den anzuzeigenden Text zu Übersetzten verwende ich einen IValueConverter der den Text entsprechend der eingestellten Sprache anpassen soll... Mein Code sieht wie folgt aus:

    Settings.xaml

    XML-Quellcode

    1. <ComboBox x:Name="ComboBoxAppTheme"
    2. VerticalAlignment="Top"
    3. Margin="0,5,0,0"
    4. SelectionChanged="ComboBoxAppTheme_SelectionChanged"
    5. ItemsSource="{x:Static metro:ThemeManager.AppThemes}"
    6. >
    7. <ComboBox.ItemTemplate>
    8. <DataTemplate>
    9. <TextBlock Text="{Binding Converter={StaticResource Converter_TranslateAppThemeName}, ConverterParameter='Name'}" />
    10. </DataTemplate>
    11. </ComboBox.ItemTemplate>
    12. </ComboBox>
    13. <TextBlock Margin="0,5,0,0" Text="{DynamicResource LocalizedString_Accent}" />
    14. <ComboBox x:Name="ComboBoxAppAccent"
    15. Margin="0,5,0,0"
    16. SelectionChanged="ComboBoxAppAccent_SelectionChanged"
    17. ItemsSource="{x:Static metro:ThemeManager.Accents}" >
    18. <ComboBox.ItemTemplate>
    19. <DataTemplate>
    20. <DockPanel>
    21. <Rectangle Width="16"
    22. Height="16"
    23. Margin="0,0,10,0"
    24. Fill="{Binding Converter={StaticResource Converter_AccentToBrush} ,ConverterParameter='Name' }"/>
    25. <TextBlock Text="{Binding Converter={StaticResource Converter_TranslateAccentName}, ConverterParameter='Name'}" />
    26. </DockPanel>
    27. </DataTemplate>
    28. </ComboBox.ItemTemplate>
    29. </ComboBox>



    IValueConverter - TranslateAccentName

    C#-Quellcode

    1. /* translate the name of the accent */
    2. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    3. {
    4. Accent accent = value as Accent;
    5. string accentName = Application.Current.Resources["LocalizedString_Accent_" + accent.Name] as string;
    6. if (string.IsNullOrEmpty(accentName))
    7. accentName = accent.Name;
    8. return accentName;
    9. }



    IValueConverter - TranslatedAppTheme

    C#-Quellcode

    1. /* translate the name of the app theme */
    2. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    3. {
    4. AppTheme appTheme = value as AppTheme;
    5. string themeName = Application.Current.Resources["LocalizedString_AppTheme_" + appTheme.Name] as string;
    6. if (string.IsNullOrEmpty(themeName))
    7. themeName = appTheme.Name;
    8. return themeName;
    9. }



    Beim Ändern der Sprache in den Einstellungen rufe ich folgenden Code auf, damit die Elemente der ComboBox Refreshed werden und somit erneut vom IValueConverter diese übersetzt...

    Code zum triggern des Converters in der ComboBox 8-)

    C#-Quellcode

    1. ICollectionView collectionView_AppAccent = CollectionViewSource.GetDefaultView(ComboBoxAppAccent.ItemsSource);
    2. collectionView_AppAccent.Refresh();
    3. ICollectionView collectionView_AppTheme = CollectionViewSource.GetDefaultView(ComboBoxAppTheme.ItemsSource);
    4. collectionView_AppTheme.Refresh();


    Jetzt zu meinem Problem... Wenn ich die Sprache änder, wird die Liste übersetzt. Nur das Ausgewählte Element in der ComboBox wird nicht "geuptaded/refreshed"



    Hat hier jemand eine Lösung für oder kann mir einen Denkanstoß geben? Bin so langsam am verzweifeln ;(

    Achja, bei Hurricane wird auch nur die Liste geupdated und nicht das ausgewählte Element... hab mir den Code schon auf GitHub angesehen und damit bisschen herumexperimentiert.

    Vielen Dank :thumbsup:

    C-Sharp
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!
    Zunächst würde ich vorschlagen, auch die Sprache, in die übersetzt werden soll, als Eigenschaft hinzuzufügen und an diese zu binden, letztendlich also mit einem MultiBinding. Auf diese Weise konnte ich problemlos an die entsprechenden Eigenschaften binden und auch die Zusammenfassung wurde aktualisiert.

    Was mir zusätzlich noch eingefallen ist, sollte der gerade angesprochene Tipp nicht anwendbar sein oder auch nicht funktionieren, könnte möglicherweise das folgende zusätzliche Binding helfen:

    XML-Quellcode

    1. <ComboBox ... Text="{Binding SelectedValue, RelativeSource={RelativeSource Self}, Converter={*Converter*}}" >
    2. ...
    3. </ComboBox>


    Text verweist auf die angesprochene Zusammenfassung, die sich bei dir nicht aktualisiert, möglicherweise hilft dieses zusätzliche Binding zur Aktualisierung, da auf das derzeit ausgewählte Element verwiesen wird.
    Für beide Beispiele habe ich in ähnlicher Form ein kleines Testprojekt erstellt, dass ich dir neben diesem Codeschnipsel gerne noch zukommen lassen kann.
    @lukekogv könntest du mir das Testprojekt mal zur Verfügung stellen? Würde mir gerne mal anschauen wie das funktioniert, obwohl ich nicht weiß ob das wirklich mein Problem beheben kann.

    Das Problem ist ja, das Sie nur der anzuzeigende Text ändert, das ausgewählte Item an sich aber immer das selbe ist (.Equals() gibt True aus). Hab jetzt in diversen Foren gelesen das mehrere Leute das Problem haben, dass das ausgewählte Item sich nicht aktualisiert, wenn man die ComboBox "refreshed".

    Quick und Dirty wäre, dass das Item kurz geändert wird mit

    C#-Quellcode

    1. int ind = cbItems.SelectedIndex;
    2. cbItems.SelectedIndex = -1;
    3. cbItems.SelectedIndex = ind;


    Davon halte ich aber persönlich nicht so viel. Hab aber mal eine ComboBox gegen ein schönes ListView ersetzt und den Namen über ein ToolTip hinzugefügt ^^:
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!
    Wie gesagt, meine erste Lösung für das Problem wäre, ein MultiBinding zu verwende mit der Sprache als Eigenschaft, an die gebunden wird. In dem Beispielprojekt habe ich keine Übersetzung eingebaut, jedoch wird ebenfalls ein Converter verwendet und eine ComboBox ändert die Einträge in einer zweiten ComboBox sowie die entsprechende Zusammenfassung. Ich werde dir das Projekt auch als PM schicken, möchte hier aber den Ansatz auch der Allgemeinheit nicht vorenthalten.

    XAML

    XML-Quellcode

    1. <Grid>
    2. <Grid.Resources>
    3. <local:StringAddConverter x:Key="stringAdd" />
    4. </Grid.Resources>
    5. <Grid.ColumnDefinitions>
    6. <ColumnDefinition Width="*" />
    7. <ColumnDefinition Width="*" />
    8. </Grid.ColumnDefinitions>
    9. <ComboBox ItemsSource="{Binding TestStrings}" SelectedValue="{Binding SelectedTestString, Mode=TwoWay}" VerticalAlignment="Center" Margin="5" />
    10. <ComboBox Grid.Column="1" ItemsSource="{Binding Names}" VerticalAlignment="Center" Margin="5">
    11. <ComboBox.ItemTemplate>
    12. <DataTemplate>
    13. <TextBlock>
    14. <TextBlock.Text>
    15. <MultiBinding Converter="{StaticResource stringAdd}">
    16. <Binding Path="DataContext.SelectedTestString" RelativeSource="{RelativeSource AncestorType=Grid}" />
    17. <Binding />
    18. </MultiBinding>
    19. </TextBlock.Text>
    20. </TextBlock>
    21. </DataTemplate>
    22. </ComboBox.ItemTemplate>
    23. </ComboBox>
    24. </Grid>

    Window und ViewModel

    C#-Quellcode

    1. [ImplementPropertyChanged]
    2. public partial class MainWindow : Window
    3. {
    4. public String SelectedTestString { get; set; }
    5. public List<String> TestStrings { get; set; }
    6. public List<String> Names { get; set; }
    7. public MainWindow()
    8. {
    9. this.Names = (new String[] { "Mark", "Lisa", "Tom" }).ToList();
    10. this.TestStrings = (new String[] { "Hello", "Hi", "Bye" }).ToList();
    11. this.DataContext = this;
    12. this.InitializeComponent();
    13. }
    14. }

    Converter

    C#-Quellcode

    1. public class StringAddConverter : IMultiValueConverter
    2. {
    3. public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    4. {
    5. return values.Select(val => (String)val).Aggregate(String.Empty, (val1, val2) => val1 + " " + val2);
    6. }
    7. public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    8. {
    9. throw new NotImplementedException();
    10. }
    11. }

    Aus Gründen der Übersichtlichkeit verwende ich in diesem Beispiel die Window-Klasse direkt als ViewModel und nutze die beiden Listen als ItemsSources für die ComboBoxes sowie die String-Eigenschaft für den momentanen Wert der ersten ComboBox, hier könnte man selbstverständlich auch direkt an die ComboBox und ihrer SelectedValue binden ;)
    Auch noch wichtig zu erwähnen ist sicherlich, dass ich Fody.PropertyChanged verwende, um mir die Implementierung der INotifyPropertyChanged-Schnittstelle zu sparen (siehe [ImplementPropertyChanged]).


    Sollten sich die Einträge aufgrund vieler verschiedener Faktoren ändern, solltest du die Generierung der einzelnen Texte möglicherweise dein ViewModel übernehmen lassen, anstatt einen Converter zu verwenden.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „lukekogv“ ()

    Habs bislang nicht hinbekommen und um keine weitere Zeit zu verschwenden auf ein ListView gewechselt, welches mir die für mich benötigte Funktion bietet.

    Anscheinend ist das von Microsoft auch nicht vorgesehen ein ausgewähltes Item zu "refreshen". Was ja eigentlich auch berechtigt ist, da es in der Source nicht geändert wurde.

    @lukekogv Trotzdem danke für deine Bemühung.
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!

    C-Sharp schrieb:

    Anscheinend ist das von Microsoft auch nicht vorgesehen ein ausgewähltes Item zu "refreshen". Was ja eigentlich auch berechtigt ist, da es in der Source nicht geändert wurde.

    Naja, wie du dem GIF oben unter "Ergebnis" entnehmen kannst, funktioniert es offensichtlich doch; das, was sich als Auslöser verändert (in deinem Fall die Sprache), muss jedoch eine DependencyProperty sein. Dieses Refreshen muss dann auch nicht manuell geschehen, sondern wird automatisch erledigt. Wenn eine ListView dir dennoch besser weiterhilft, ist das natürlich auch in Ordnung :)