在ItemsSource更新后,WPF ComboBox设置为null

时间:2016-08-04 22:25:37

标签: c# wpf xaml mvvm combobox

我在WPF应用中遇到了ComboBox。它与其他一些问题类似,但这个问题的经典解决方案似乎并没有起作用。

基本上,它与此问题相同:

WPF ComboBox SelectedItem Set to Null on TabControl Switch

但是,我的ItemsSource已经在SelectedItem之后的XAML中,这通常是对它进行排序。

发生的事情是我有一个带有组合框的视图,数据已经加载,然后一个事件被触发,更新了提供给ComboBox的数据。 ViewModel使用事件(由获取数据的BackgroundWorker触发)并更新其ObservableCollection,即带有新数据的ItemsSource。像这样:

int id = (int)Invoice.Customer.DatabaseID;
Customers = new ObservableCollection<Customer>(customers);
Invoice.Customer = Customers.FirstOrDefault(x => x.DatabaseID == id);

正如您所看到的,它会尝试将发票上的客户设置回原来的状态。这确实发生了,但是,在断点处观察到,但是,一旦完成,Customer就会从未识别的源中恢复为null(我的代码中没有一个出现在调用堆栈中,它是所有框架内容)。

ComboBox的XAML是:

<ComboBox DisplayMemberPath="AccountCode"
    SelectedItem="{Binding Invoice.Customer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
    ItemsSource="{Binding Customers}"/>

总而言之,我的ComboBox SelectedItem在ItemsSource更新后设置为null,并确保ItemsSource在SelectedItem不执行任何操作之后。我真的无法弄清楚为什么它被设置为空,我不确定在哪里看。我可以看到任何指针或事物,以便找到解决方案,这将非常感激。

编辑:好的,我已经玩了一些,我怀疑它与来自BackgroundWorker的更新有关。我在数据服务中使用Timer和BackgroundWorker定期更新数据库中的客户列表,以确保数据相对最新。 BackgroundWorker在完成时触发事件,以通知感兴趣的对象列表已更新。这似乎意味着当事件被消耗时,它们处于不同的线程中。当它以这种方式更新时,我将SelectedItem设置为正确的项后将其设置为null,因此将Invoice.Customer设置为null。我在我的视图中快速添加了一个按钮来更新客户而不使用BackgroundWorker,这似乎每次都有效。我想定期更新数据,但我需要先解决这个问题。

3 个答案:

答案 0 :(得分:0)

好吧,正如我在编辑中所怀疑的那样,这与某些方式的线程有关。在更新被计时器启动后更新ComboBox ItemsSource,导致它在更新为正确的客户后设置为null。我在一个新的应用程序中确认了这种行为,它没有包含其中的所有其他内容,因此我可能会将其设置为null,我并不意味着(即使调用堆栈似乎强烈建议它我不这样做。)当事件被触发以更新结果时,与真实应用程序相比,我在新应用程序中获得了完全相同的调用堆栈。

在玩了一些不同的东西之后,我已经遇到过这种方法(在我的应用程序中 - 没有将它部署到真正的应用程序中,但是手指越过它也可以在那里工作!)就是让事件发生了通过TaskFactory进行竞争更新(来自Is it wrong to use the Dispatcher within my ViewModel?的想法)。

在ViewModel中声明一个TaskFactory:

TaskFactory uiFactory;

在你的构造函数中设置如下:

uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());

然后,如果在数据更新后运行,请执行以下操作:

private void AsyncMethods_TaskCompleted(object sender, EventArgs e)
{
    uiFactory.StartNew( () => UpdateResults());
}

此上下文中的UpdateResults与更新发票上的客户相同。它获取旧id,将ItemsSource设置为新集合,然后将绑定到SelectedItem的属性设置为新集合中的等效项。这似乎是有效的,并没有给我以前的奇怪的行为。我将它部署到实际的应用程序,并希望它也在那里工作。如果确实如此,我会回来接受这个答案。

答案 1 :(得分:-1)

有时当你创造一个新的&#39;一个Object的实例,它可以破坏你的绑定。您可以更新现有的收藏集,而无需拨打新的&#39;或者,您可以使ObservableCollection成为依赖项属性。

答案 2 :(得分:-1)

问题是由这两行引起的。

Customers = new ObservableCollection<Customer>(customers);
Invoice.Customer = Customers.FirstOrDefault(x => x.DatabaseID == id);

您的组合框源Customers,您再次初始化它。然后,您尝试从新初始化的成员中获取数据。新初始化的成员将没有数据。

Customers中没有数据。因此Invoice.Customer可能为空。

我不明白为什么要对其进行初始化,只是尝试从中获取数据。你跳过来填补资料来源吗?

如果您错过了填充源,请先填充数据源。然后,您可以运行此代码而无需再次初始化它,以便Invoice.Customer不为空。

Invoice.Customer = Customers.FirstOrDefault(x => x.DatabaseID == id);