2016-08-04 44 views
0

我有一个与WPF应用程序中的ComboBox斗争。它类似于其他一些问题,但是这个问题的经典解决方案似乎没有工作。WPF组合框设置为null后ItemsSource更新

从本质上讲,这是同样的问题,因为这:

WPF ComboBox SelectedItem Set to Null on TabControl Switch

然而,我的ItemsSource已经在以后的SelectedItem的XAML,这是正常排序了这一点。

发生了什么事情是我有一个视图,其上已经装载了数据的组合框,然后触发一个事件来更新输入到组合框中的数据。 ViewModel使用事件(由获取数据的BackgroundWorker触发)并使用新数据更新其作为ItemsSource的ObservableCollection。像这样:

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

正如您所看到的,它试图将发票上的客户设置回原来的状态。这种情况确实发生,在断点处观察到,但是,只要完成此操作,客户就会从未识别的源(我的代码不会出现在调用堆栈中,它全部是框架内容)被设置为null。

的组合框的XAML是:

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

所以总结一下,我的组合框的SelectedItem被设置为NULL的ItemsSource更新完毕后,并确保的ItemsSource是的SelectedItem什么都不做了。我真的不知道为什么它被设置为空,我不知道在哪里看。任何指针或事情,我可以看看,以找到解决办法,将不胜感激。

编辑:好的,我一直在玩它多一点,我怀疑它与来自BackgroundWorker的更新有关。我在我的数据服务中使用Timer和BackgroundWorker来定期更新数据库中的客户列表,以确保数据相对最新。 BackgroundWorker在完成时触发事件以通知感兴趣的对象该列表已更新。这似乎意味着,当事件消耗时,它们处于不同的线程中。当它以这种方式更新时,SelectedItem在我将其设置为正确的项目并因此将Invoice.Customer设置为null后被设置为null。我很快在视图中添加了一个按钮,以便在不使用BackgroundWorker的情况下更新客户,这似乎每次都有效。我想定期更新数据,但我必须先弄清楚这一点,然后才能做到这一点。

+0

我更新了我的ItemsSource,并且我的SelectedItem保持它应该在的位置。不能重现你的问题。显示Invoice.Customer属性的定义。 – AnjumSKhan

回答

-1

好的,正如我在编辑中所怀疑的,这是以某种方式进行线程处理的。在更新被定时器启动后更新组合框ItemsSource会导致它在更新到正确的Customer后设置为空。我在一个新的应用程序中证实了这种行为,它没有其他所有的位,因此我可能会将它设置为null,我不打算这样做(尽管调用堆栈似乎严重暗示它不是我正在做)。当事件触发以更新结果时,我看到了新应用中与真实应用相比完全相同的调用堆栈。

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

在视图模型声明TaskFactory:

TaskFactory uiFactory; 

在构造函数中设置它是这样的:

uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); 
在运行中的数据已经更新做这样的事情后,事件

然后:

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

而且UpdateResults在这方面是一样的更新T上的客户他发票。它获取旧ID,将ItemsSource设置为新集合,然后将绑定到SelectedItem的属性设置为新集合中的等效项目。这似乎是工作,并没有给我我以前有过的奇怪行为。我将把它部署到实际的应用程序,并希望它也能在那里工作。如果是这样,我会回来接受这个答案。

-1

有时,当您创建Object的“新”实例时,它可能会破坏绑定。您可以更新现有Collection而不调用“new”,或者可以使ObservableCollection成为依赖项属性。

-1

这个问题是由这两行引起的。

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

你的组合框源是Customers和你再次对其进行初始化。然后,您尝试从新初始化的成员获取数据。新初始化的成员将没有数据。

ie Customers里面没有数据。因此Invoice.Customer可能会为空。

我不明白你为什么初始化它,只是试图从中获取数据。你是否跳过填写源代码?

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

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

来源已满。我可能没有很好地解释这一点,但我在Invoice.Customer集上划了一个断点。它按照预期设置客户(来自Invoice.Customer = ...),但随后它被设置为null,我认为它是框架中的东西,因为堆栈跟踪只有外部代码。 – Tominator

+0

框架如何设置它?不可能。一个属性永远不能是这样的null。也许你在代码本身的某个地方设置为null。 – ViVi

+0

如果你把ItemsSource放在XAML中的SelectedItem之前,那么它可以把它自己设置为null,就像我链接的问题一样。我还没有做到这一点,但我仍然把我的SelectedItem设置为空,它不是我能找到的代码中的任何地方。 – Tominator

相关问题