WPF standard ComboBox Items Source Change Issue
2015-07-16 13:47
531 查看
Today I encountered an issue with the WPF standard CombBox where if the bound ItemsSource (collection) of a ComboBox has changed the binding on the SelectedItem of the ComboBox will fail to update to the already properly set view model property.
For example if the ItemsSource is bound to the following property of the view model which is common and presumably the best practice:
And the SelectedItem is bound to
And the SelectedModel can be changed this way:
where each SelectedItem on SelectedModel has already been properly set up.
One might suppose it would work. However it doesn't.
The reason is kind of explained in this article,
http://stackoverflow.com/questions/5242275/combobox-itemssource-changed-selecteditem-is-ruined
As I've done a few experiments, I have feeling that the (initial) binding update is lost due to the fact that the framework modifies the SelectedItem property and holds certain assumptions as to the modification during the collection (Items) change and neglects property changed notification afterwards if things went against its assumption (no matter when it happens, and only not when the property actually changes from its value as of the end of the collection process).
Given the above speculation, I continued playing with the code and eventually come up with a workable solution like below (complete source code).
View model:
Model:
View:
For example if the ItemsSource is bound to the following property of the view model which is common and presumably the best practice:
public ObservableCollection<string> Items { get; private set; }
And the SelectedItem is bound to
public string SelectedItem { get { return SelectedModel.SelectedItem; } set { SelectedModel.SelectedItem = value; OnPropertyChanged(); } }
And the SelectedModel can be changed this way:
public Model SelectedModel { get { return _selectedModel; } set { if (_selectedModel != value) { _selectedModel = value; Items.Clear(); foreach (var item in _selectedModel.Items) { Items.Add(item); } OnPropertyChanged("SelectedItem"); } } }
where each SelectedItem on SelectedModel has already been properly set up.
One might suppose it would work. However it doesn't.
The reason is kind of explained in this article,
http://stackoverflow.com/questions/5242275/combobox-itemssource-changed-selecteditem-is-ruined
As I've done a few experiments, I have feeling that the (initial) binding update is lost due to the fact that the framework modifies the SelectedItem property and holds certain assumptions as to the modification during the collection (Items) change and neglects property changed notification afterwards if things went against its assumption (no matter when it happens, and only not when the property actually changes from its value as of the end of the collection process).
Given the above speculation, I continued playing with the code and eventually come up with a workable solution like below (complete source code).
View model:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using ComboBoxItemsSourceChangeTest.Annotations; namespace ComboBoxItemsSourceChangeTest { /// <summary> /// The view model of the main UI /// </summary> /// <remarks> /// http://stackoverflow.com/questions/5242275/combobox-itemssource-changed-selecteditem-is-ruined /// </remarks> public class MainViewModel : INotifyPropertyChanged { private Model _selectedModel; private bool _isComboTransitioning; public MainViewModel() { Items = new ObservableCollection<string>(); } public Model SelectedModel { get { return _selectedModel; } set { if (_selectedModel != value) { _selectedModel = value; _isComboTransitioning = true; Items.Clear(); foreach (var item in _selectedModel.Items) { Items.Add(item); } _isComboTransitioning = false; OnPropertyChanged("SelectedItem"); } } } public ObservableCollection<string> Items { get; private set; } public string SelectedItem { get { return _isComboTransitioning ? null: SelectedModel.SelectedItem; } set { if (SelectedModel.SelectedItem != value && !_isComboTransitioning) { SelectedModel.SelectedItem = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } public void RaisePropertyChanged(string propertyName) { OnPropertyChanged(propertyName); } } }
Model:
namespace ComboBoxItemsSourceChangeTest { public class Model { public string[] Items { get; set; } public string SelectedItem { get; set; } } }
View:
<Window x:Class="ComboBoxItemsSourceChangeTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <StackPanel> <ComboBox Margin="10" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" Name="ComboBox1"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"></TextBlock> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> <Button Margin="10" Name="Button1" Click="Button1_Click">Data Source 1</Button> <Button Margin="10" Name="Button2" Click="Button2_OnClick">Data Source 2</Button> <Button Margin="10" Name="Button3" Click="Button3_OnClick">Data Source 3</Button> <Button Margin="10" Name="ButtonRandomSelect" Click="ButtonRandomSelect_OnClick">Random Select</Button> </StackPanel> </Grid> </Window>
相关文章推荐
- Android中使用Handler机制更新UI的三种解决方案
- UITableViewCell中的imageView固定大小
- Android UI学习之RadioButton和RadioGroup
- (C#)使用队列(Queue)解决简单的并发问题
- Mac下的UI自动化测试 (四)
- iOS UILocalNotification 多个本地通知,怎么有区分的删除
- POJ 2299 Ultra-QuickSort 树状数组,归并排序
- iOS数组count操作(NSUInteger)的安全性
- 如何更好地限制一个UITextField的输入长度
- SAP GUI FOR HTML登陆 (转)
- Windows 10 build 10240预览版上手操作视频
- 玩转iOS 9的UIDynamics
- iOS开发UI技巧篇 -- UILable
- Mac下的UI自动化测试 (三)
- JS生成UUID
- kqueue示例
- Null value was assigned to a property of primitive type setter of cn.itcast.oa.domain.Forum.topicCount
- Win10 Build 10240改进汇总:浏览器性能提升
- [Poj2478]Farey Sequence
- 设置UITableViewCell背景色