UWP reflects the selected CombBox item loaded from settings through binding

This is a continuation from an earlier question .

For some application settings, I want to use ComboBox to select an option. I can save the selected option (roaming) and load it again. The loaded option displays correctly in the TextBlock, but the ComboBox shows a space. How can I also reflect the loaded parameter currently selected in ComboBox?

This is XAML:

<Page x:Class="ComboBoxTest.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:ComboBoxTest" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:converter="using:ComboBoxTest.Converter" mc:Ignorable="d"> <Page.Resources> <converter:ComboBoxItemConvert x:Key="ComboBoxItemConvert" /> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel> <ComboBox Name="ComboBox" ItemsSource="{x:Bind ComboBoxOptions}" SelectedItem="{x:Bind SelectedComboBoxOption, Mode=TwoWay, Converter={StaticResource ComboBoxItemConvert}}" SelectedValuePath="ComboBoxOption" DisplayMemberPath="ComboBoxHumanReadableOption" Header="ComboBox" > </ComboBox> <TextBlock Name="BoundTextblock" Text="{x:Bind SelectedComboBoxOption.ComboBoxOption, Mode=OneWay}"/> </StackPanel> </Grid> 

And this is the code:

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using System.Xml.Serialization; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.Storage; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 namespace ComboBoxTest { /// <summary> /// An empty page that can be used on its own or navigated to within a Frame. /// </summary> public sealed partial class MainPage : Page, INotifyPropertyChanged { ApplicationDataContainer roamingSettings = null; private ObservableCollection<ComboBoxItem> ComboBoxOptions; public MainPage() { this.InitializeComponent(); ComboBoxOptions = new ObservableCollection<ComboBoxItem>(); ComboBoxOptionsManager.GetComboBoxList(ComboBoxOptions); roamingSettings = ApplicationData.Current.RoamingSettings; var value = (string)roamingSettings.Values["ComboBoxSelection"]; if (value != null) { SelectedComboBoxOption = Deserialize<ComboBoxItem>(value); //loaded selection reflected in the textbox but not in the ComboBox } else { SelectedComboBoxOption = ComboBoxOptions[0]; } } public class ComboBoxItem { public string ComboBoxOption { get; set; } public string ComboBoxHumanReadableOption { get; set; } } public class ComboBoxOptionsManager { public static void GetComboBoxList(ObservableCollection<ComboBoxItem> ComboBoxItems) { var allItems = getComboBoxItems(); ComboBoxItems.Clear(); allItems.ForEach(p => ComboBoxItems.Add(p)); } private static List<ComboBoxItem> getComboBoxItems() { var items = new List<ComboBoxItem>(); items.Add(new ComboBoxItem() { ComboBoxOption = "Option1", ComboBoxHumanReadableOption = "Option 1" }); items.Add(new ComboBoxItem() { ComboBoxOption = "Option2", ComboBoxHumanReadableOption = "Option 2" }); items.Add(new ComboBoxItem() { ComboBoxOption = "Option3", ComboBoxHumanReadableOption = "Option 3" }); return items; } } private ComboBoxItem _SelectedComboBoxOption; public ComboBoxItem SelectedComboBoxOption { get { return _SelectedComboBoxOption; } set { if (_SelectedComboBoxOption != value) { _SelectedComboBoxOption = value; roamingSettings.Values["ComboBoxSelection"] = Serialize(value); RaisePropertyChanged("SelectedComboBoxOption"); } } } public static string Serialize(object obj) { using (var sw = new StringWriter()) { var serializer = new XmlSerializer(obj.GetType()); serializer.Serialize(sw, obj); return sw.ToString(); } } public static T Deserialize<T>(string xml) { using (var sw = new StringReader(xml)) { var serializer = new XmlSerializer(typeof(T)); return (T)serializer.Deserialize(sw); } } void RaisePropertyChanged(string prop) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } public event PropertyChangedEventHandler PropertyChanged; } } 
+5
source share
1 answer

This is a typical case of elements that look the same, but not because they have different links (read C # reference types ).

You load a ComboBox with three values, and these 3 values ​​are displayed in a drop-down list. To see the selected item when the ComboBox closed, it must be (= have the same link) as one of these 3 values. If nothing is saved in the roaming settings, you select the first option as SelectedItem . By switching to another selected item, you will also receive a valid link in the SelectedItem property.

However, when deserializing the saved RoamingSettings value RoamingSettings you create a new object with a different reference. When you set this element as SelectedItem , the ComboBox control will not find it in its elements and therefore will not select the element.

To fix this, you need to find the correct item in the ItemSource collection:

 var value = (string)roamingSettings.Values["ComboBoxSelection"]; if (value != null) { var deserialized = Deserialize<ComboBoxItem>(value); // using ComboBoxOption as the primary key field of your object SelectedComboBoxOption = ComboBoxOptions.SingleOrDefault(c => c.ComboBoxOption == deserialized.ComboBoxOption); } else { SelectedComboBoxOption = ComboBoxOptions[0]; } 
+6
source

Source: https://habr.com/ru/post/1236556/


All Articles