WPF ComboBox component resets the selected item when the source item changes

Consider the following XAML:

<ComboBox Name="CompanyComboBox" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=GlobalData.Companies}" SelectedValuePath="Id" SelectedValue="{Binding Customer.CompanyId, ValidatesOnDataErrors=True}" DisplayMemberPath="Name" /> 

GlobalData.Companies is a collection of ( IEnumerable<Company> ) companies; this collection can be reloaded in the background (it is downloaded from a web service). When this happens, the ComboBox correctly reloads the elements through binding. However, as a side effect, it also discards the selected item!

I used Reflector to check the combo-box sources and this is apparently the intended behavior.

Is there a โ€œgoodโ€ way around this? What I want to achieve is that if the user selects "Company A" and reloads the list of companies, then "Company A" remains selected (if it is in the new list).

+6
wpf combobox selecteditem
source share
3 answers

Perhaps you can use ObservableCollection<Company> instead of your IEnumerable<Company> ? Then, when changing the background, you only add / remove items that are new / absent in the new list, the selected item should remain, unless this has been deleted.

You can update your observed collection in a separate thread with a little hack .

+4
source share

hmm, I donโ€™t know if this is a โ€œgoodโ€ way, but if you can access the selected item before rebooting, you can save it (or its key or something else) and select it again after the reboot is performed.

quick layout:

 var selectedItem = myCombo.SelectedItem; DoReload(); myCombo.SelectedItem = selectedItem; 

But I guess you mean a different way, how does this guide work?
Hope this helps anyway ...

UPDATE
Ok, I see from the background thread.
Do you use ICollectionView to bind dropdowns? If so, you can use the CurrentItem property to save the link. I made a quick layout and it works on my setup. this assumes you have a link to your interface:

Xaml

 <Grid VerticalAlignment="Top"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <ComboBox ItemsSource="{Binding Items}" IsSynchronizedWithCurrentItem="True" Grid.Column="0" Grid.Row="0" DisplayMemberPath="Name"/> <Button Command="{Binding UpdateCommand}" Grid.Column="1" Grid.Row="0">Update</Button> </Grid> 

View / ViewModel

 public partial class Window1 : Window { public Window1() { InitializeComponent(); this.DataContext = new ViewModel(this); } } public class ViewModel { private readonly Window1 window; private ObservableCollection<Item> items; private ICollectionView view; public ViewModel(Window1 window) { this.window = window; items = new ObservableCollection<Item> { new Item("qwerty"), new Item("hello"), new Item("world"), }; view = CollectionViewSource.GetDefaultView(items); } public ObservableCollection<Item> Items { get { return items; } } public ICommand UpdateCommand { get { return new RelayCommand(DoUpdate); } } public Item SelectedItem { get; set; } private void DoUpdate(object obj) { var act = new Func<List<Item>>(DoUpdateAsync); act.BeginInvoke(CallBack, act); } private List<Item> DoUpdateAsync() { return new List<Item> { new Item("hello"), new Item("world"), new Item("qwerty"), }; } private void CallBack(IAsyncResult result) { try { var act = (Func<List<Item>>)result.AsyncState; var list = act.EndInvoke(result); window.Dispatcher.Invoke(new Action<List<Item>>(delegate(List<Item> lst) { var current = lst.Single(i => i.Name == ((Item)view.CurrentItem).Name); Items.Clear(); lst.ForEach(Items.Add); view.MoveCurrentTo(current); }), list); } catch(Exception exc){ Debug.WriteLine(exc); } } } public class Item { public Item(string name) { Name = name; } public string Name { get; set; } } 

You will need to do some processing if the selected item is no longer listed.
The IsSynchronizedWithCurrentItem property is important here, otherwise it will not work!
In addition, the way the main window refers should be with a DI framework.

0
source share

As Yakoder noted, this is due to the equality of objects. As long as you bind SelectedValue instead of SelectedItem, you can define ItemsSource as a collection of an anonymous type. Then this problem will not occur (and it is also faster if you need to read values โ€‹โ€‹from the database).

0
source share

All Articles