考虑以下XAML:
<ComboBox Name="CompanyComboBox"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Path=GlobalData.Companies}"
SelectedValuePath="Id"
SelectedValue="{Binding Customer.CompanyId, ValidatesOnDataErrors=True}"
DisplayMemberPath="Name" />
GlobalData.Companies
是公司的集合(IEnumerable<Company>
);此集合可以在后台重新加载(从Web服务下载)。发生这种情况时,ComboBox会通过绑定正确地重新加载项目。但是作为副作用,它还会重置所选项目!
我使用Reflector来检查组合框源,显然这是预期的行为。
有什么“好”的方式来解决这个问题吗?我想要实现的是,如果用户选择“公司A”并在之后重新加载公司列表,则“公司A”保持选中状态(假设它在新列表中)。
答案 0 :(得分:4)
也许您可以使用ObservableCollection<Company>
而不是IEnumerable<Company>
?然后,在后台更改时,您只会添加/删除新列表中新/不存在的项目,所选项目应保留,除非更改已删除它。
你可以update your observable collection in a separate thread with a small hack-around。
答案 1 :(得分:3)
请尝试使用以下代码。 将以下属性启用到组合框
IsSynchronizedWithCurrentItem="True"
答案 2 :(得分:0)
快速模型:
var selectedItem = myCombo.SelectedItem;
DoReload();
myCombo.SelectedItem = selectedItem;
但我认为你的意思不同于本手册的另一种方法? 希望无论如何都有帮助...
<强>更新强>
好的,我从背景线程看到
您是否也使用ICollectionView来绑定组合框?如果是这样,您可以使用CurrentItem属性来保留引用。我做了一个快速的模型,这正在我的设置。假设您有对UI的引用:
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>
查看/ 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; }
}
如果所选项目不在列表中,您将需要进行一些处理
IsSynchronizedWithCurrentItem 属性在这里很重要,否则它将无效!
此外,对主窗口的引用的方式应该是DI框架。
答案 3 :(得分:0)
正如Yacoder所指出,这与对象平等有关。只要绑定SelectedValue而不是SelectedItem,就可以将ItemsSource定义为匿名类型集合。然后不会发生此问题(如果您需要从数据库中读取值,它也会更快)。