首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ItemsSource更新后,WPF ComboBox设置为null

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

Stack Overflow用户
提问于 2016-08-05 06:25:37
回答 3查看 1.3K关注 0票数 1

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

从本质上讲,这和下面的问题是一样的:

WPF ComboBox SelectedItem Set to Null on TabControl Switch

但是,我的ItemsSource已经在SelectedItem之后的XAML中了,这通常是解决这个问题的方法。

发生的事情是,我有一个带有组合框的视图,上面已经加载了数据,然后触发一个事件,该事件更新馈送到ComboBox的数据。ViewModel使用事件(由获取数据的BackgroundWorker触发),并使用新数据更新其ObservableCollection (即ItemsSource )。如下所示:

代码语言:javascript
运行
复制
int id = (int)Invoice.Customer.DatabaseID;
Customers = new ObservableCollection<Customer>(customers);
Invoice.Customer = Customers.FirstOrDefault(x => x.DatabaseID == id);

正如您所看到的,它试图将发票上的客户设置回最初的状态。这种情况确实会发生,但有一个断点,一旦完成,客户就会从一个不确定的来源重新设置为null (我的代码都没有出现在调用堆栈中,都是框架的东西)。

ComboBox的XAML是这样的:

代码语言:javascript
运行
复制
<ComboBox DisplayMemberPath="AccountCode"
    SelectedItem="{Binding Invoice.Customer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
    ItemsSource="{Binding Customers}"/>

总而言之,我的ComboBox SelectedItem在ItemsSource更新后被设置为null,并确保ItemsSource在SelectedItem什么也不做之后。我真的不明白为什么它会被设置为null,我也不确定要去哪里查找。为了找到解决这个问题的方法,我会非常感谢你的任何指点或我能看的东西。

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-08-05 22:35:05

好吧,正如我在我的编辑中怀疑的那样,这与线程以某种方式有关。在定时器启动更新后,从更新ComboBox ItemsSource会导致在更新到正确的客户后将其设置为null。我在一个新的应用程序中确认了这一行为,该应用程序没有包含所有其他部分,因此我可能会将其设置为null,这不是我想要的(即使调用堆栈似乎强烈表明不是我在做这件事)。当触发事件来更新结果时,我得到了与真正的应用程序相比,在fresh应用程序中看起来完全相同的调用堆栈。

在玩弄了一些不同的东西之后,我发现了这个方法(在我的新应用程序中-没有将它部署到真正的应用程序中,但手指祈祷它也能在那里工作!)是通过一个TaskFactory (idea from here Is it wrong to use the Dispatcher within my ViewModel?)通过竞争更新来触发事件。

在ViewModel中声明一个TaskFactory:

代码语言:javascript
运行
复制
TaskFactory uiFactory;

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

代码语言:javascript
运行
复制
uiFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());

然后,在数据更新后运行的事件中,执行如下操作:

代码语言:javascript
运行
复制
private void AsyncMethods_TaskCompleted(object sender, EventArgs e)
{
    uiFactory.StartNew( () => UpdateResults());
}

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

票数 0
EN

Stack Overflow用户

发布于 2016-08-05 08:03:53

有时,当你创建一个对象的“新”实例时,它会破坏你的绑定。您可以更新现有的集合而不调用“new”,也可以将ObservableCollection设置为依赖项属性。

票数 -1
EN

Stack Overflow用户

发布于 2016-08-05 11:23:28

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

代码语言:javascript
运行
复制
Customers = new ObservableCollection<Customer>(customers);
Invoice.Customer = Customers.FirstOrDefault(x => x.DatabaseID == id);

您的combobox源代码是Customers,并且您正在再次初始化它。然后,您尝试从一个新初始化的成员获取数据。新初始化的成员将不包含任何数据。

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

我不明白为什么你初始化它,然后简单地尝试从它获取数据。你跳过填充源代码了吗?

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

代码语言:javascript
运行
复制
Invoice.Customer = Customers.FirstOrDefault(x => x.DatabaseID == id);
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38778356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档