2016-08-04 4 views
0

У меня есть борьба с ComboBox в приложении WPF. Это похоже на некоторые другие вопросы, но классическое решение этой проблемы, похоже, не работает.Настройка WPF ComboBox на null после обновления ItemsSource

По сути, это та же проблема, как это:

WPF ComboBox SelectedItem Set to Null on TabControl Switch

Однако моя ItemsSource уже в XAML после SelectedItem, который является тем, что обычно сортирует это.

Что происходит, так это то, что у меня есть представление со списком на нем с уже загруженными данными, после чего запускается событие, которое обновляет данные, подаваемые в ComboBox. ViewModel расходует событие (запущено BackgroundWorker, которое получает данные) и обновляет свой ObservableCollection, который является ItemsSource с новыми данными. Пример:

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

Как вы можете видеть, он пытается вернуть Заказчика в счет-фактуру обратно к исходному. Однако это происходит, наблюдаемый с точкой прерывания, однако, как только это будет завершено, клиент получает значение null от неизвестного источника (ни один из моих кодов не отображается в стеке вызовов, это все фреймворк).

Часть XAML для ComboBox это:

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

Итак, подведем итог, мой ComboBox SelectedItem получает значение NULL после ItemsSource обновляется и обеспечение ItemsSource после SelectedItem ничего не делает. Я действительно не могу понять, почему он получает значение null, и я не уверен, где искать. Любые указатели или вещи, на которые я могу смотреть, чтобы найти решение этого, будут очень признательны.

EDIT: Хорошо, я играл с ним немного больше, и я подозреваю, что это имеет какое-то отношение к обновлению, исходящему из BackgroundWorker. Я использую Timer и BackgroundWorker в своей службе данных, чтобы периодически обновлять список клиентов из базы данных, чтобы гарантировать, что данные относительно текущие. BackgroundWorker запускает событие, когда оно завершено, чтобы сообщить заинтересованным объектам, что список был обновлен. Это означает, что когда события расходуются, они находятся в другом потоке. Когда он обновляет этот способ, SelectedItem получает значение null после того, как я установил его в правильный элемент и, следовательно, устанавливает Invoice.Customer в null. Я быстро добавил кнопку к моему представлению, чтобы обновлять клиентов, не используя BackgroundWorker, и это, кажется, работает каждый раз. Я хотел бы периодически обновлять данные, но мне нужно понять это, прежде чем я смогу это сделать.

+0

Я обновил свои ItemsSource, и мой SelectedItem остается там, где он должен быть. Не могу воспроизвести вашу проблему. Показать определение свойства Invoice.Customer. – AnjumSKhan

ответ

-1

ОК, как я подозревал в своем редактировании, это было связано с нарезкой в ​​некотором роде. Обновление ComboBox ItemsSource после того, как обновление было выпущено таймером, вызывало у него значение 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()); 
} 

И UpdateРезультаты в этом контексте такие же, как обновление Клиента по t он Счет. Он получает старый идентификатор, устанавливает ItemSource в новую коллекцию, а затем устанавливает свойство, привязанное к SelectedItem, к эквивалентному элементу новой коллекции. Кажется, это работает и не дает мне странного поведения, которое я имел раньше. Я собираюсь развернуть его в реальном приложении и надеюсь, что он там тоже работает. Если это произойдет, я вернусь и приму этот ответ.

-1

Иногда, когда вы создаете «новый» экземпляр объекта, он может сломать ваши привязки. Вы можете обновить существующую коллекцию без вызова «нового» ИЛИ вы можете сделать свойство зависимостей ObservableCollection зависимым.

-1

Проблема вызвана этими двумя строками.

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

Ваш источник выпадающий является Customers и вы его инициализации снова. Затем вы пытаетесь извлечь данные из недавно инициализированного элемента. Вновь инициализированный член не будет иметь данных.

ie Customers не имеет данных. Следовательно, Invoice.Customer, вероятно, будет null.

Я не понимаю, почему вы его инициализируете и просто пытаетесь получить данные от него. Вы пропустили, чтобы заполнить источник?

Если вы пропустили, чтобы заполнить источник, сначала заполните источник данными. Затем вы можете запустить этот код, не инициализируя его снова, чтобы Invoice.Customer не был нулевым.

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

Источник заполнен. Я, возможно, недостаточно объяснил это, но поставил точку останова на наборе Invoice.Customer. Он устанавливает клиента как ожидалось (из Invoice.Customer = ...), но затем он получает значение null для чего-то еще, и я предполагаю, что это что-то в рамках, поскольку трассировка стека имеет только внешний код. – Tominator

+0

Каким образом инфраструктура может быть установлена ​​так? Это невозможно. Свойство никогда не может быть нулевым. Возможно, вы устанавливаете нуль где-то в своем коде. – ViVi

+0

Если вы помещаете ItemSource в SelectedItem в XAML, тогда он может устанавливать вещи в нуль самостоятельно, как в вопросе, который я связал. Я не делал этого здесь, но я все равно получаю, чтобы мой SelectedItem был установлен в null, и это не из моего кода, который я могу найти. – Tominator

Смежные вопросы