Доброе утро,
Извинения за массу текста, которую я собираюсь предоставить, но ...
У меня есть WPF ListView с его ItemsSource, связанным с ObservableCollection в его соответствующей ViewModel.Когда окно загружается, наблюдаемая коллекция заполняется из веб-службы с помощью команды.Однако во время работы программы эта коллекция периодически обновляется потоком BackgroundWorker для добавления новых элементов в коллекцию ObservableCollection.
Этот механизм работает нормально.ListView обновляется без проблем как в потоке пользовательского интерфейса, так и в фоновом потоке.Однако при двойном щелчке по элементу в ListView открывается новое окно для отображения сведений об объекте Ticket, содержащемся в вышеупомянутой коллекции ObservableCollection.
У меня есть частный метод, который запускается каждый раз, когда вызывается метод set ObservableCollection, который служит для поиска элемента Ticket из коллекции, которая была открыта в новом окне, и обновления его свойств в соответствии с элементами внедавно обновленная коллекция ObservableCollection.Перед выполнением этого обновления я проверяю, чтобы значение ObservableCollection.Count было больше 1, нет смысла делать обновление, если обновлять нечего!
Моя проблема в том, что свойство ObservableCollection.Count ВСЕГДА равнов 0. Но я знаю, что это не так, поскольку ListView по-прежнему обновляет свои элементы новыми объектами Ticket, добавленными в эту коллекцию. Если счет этой коллекции действительно равен 0, то это будет отражено в ListView, также не имеющем элементовв нем, как оно связано с этой коллекцией.
Так что здесь происходит?Мне интересно, может быть, потому что BackgroundWorker вызывает;
myCollection = new ObservableCollection();
в потоке, отличном от пользовательского интерфейса, что когда я проверяю счет в потоке пользовательского интерфейса, неправильный объект коллекции фактически проверяется на «Count».Но это по-прежнему не объясняет, почему ListView отражает содержимое ObservableCollection без проблем.
Опять же, извиняюсь за стену, но я хотел полностью объяснить эту проблему.Благодарим Вас за потраченное время и любые предоставленные вами данные.
РЕДАКТИРОВАТЬ БОЛЬШЕ ДЕТАЛЕЙ
Раздел просмотра списка пользовательского элемента управления
<ListView x:Name="lvTicketSummaries" ItemsSource="{Binding Path=TicketSummaries}" Grid.Row="1" Width="Auto" Height="Auto" SizeChanged="lvTicketSummaries_SizeChanged" SelectionMode="Single" Foreground="Black" Background="#3BFFFFFF" ItemContainerStyle="{DynamicResource ListViewItem}">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="ID"
DisplayMemberBinding="{Binding ID}"
Width="25"/>
<GridViewColumn Header="Status"
DisplayMemberBinding="{Binding Status}"
Width="25"/>
<GridViewColumn Header="Subject"
DisplayMemberBinding="{Binding Subject}"
Width="25"/>
<GridViewColumn Header="Requester"
DisplayMemberBinding="{Binding Owner.Name}"
Width="25"/>
</GridView>
</ListView.View>
</ListView>
Модель представления вышеупомянутого пользовательского элемента управления
Здесь вы видите коллекцию TicketSummaries, с которой связано представление списка, а также метод refreshOpenTicket (), используемый для обновлениясвойство Ticket в дочерней модели представления, которая представляет собой новый экземпляр новой обновленной коллекции.
public class MainWindowViewModel : ViewModelBase
{
private DispatcherTimer timer;
private BackgroundWorker worker_TicketLoader;
private ObservableCollection<Ticket> ticketSummaries;
public ObservableCollection<Ticket> TicketSummaries
{
get { return ticketSummaries; }
set
{
ticketSummaries = value;
this.RaisePropertyChanged(p => p.TicketSummaries);
refreshOpenTicket();
}
}
private void refreshOpenTicket()
{
// Check there are actually some tickets to refresh
if (TicketSummaries.Count < 1)
return;
// Check we have created the view model
if (TicketDetailsViewModel != null)
{
// Check the ticket loaded correctly
if (TicketDetailsViewModel.Ticket != null)
{
// Find a ticket in the collection with the same id
Ticket openTicket = TicketSummaries.Where(
ticket => ticket.ID == TicketDetailsViewModel.Ticket.ID
).First();
// Make sure we are not going to overrite with a null reference
if (openTicket != null)
TicketDetailsViewModel.Ticket = openTicket;
}
}
}
Эта коллекция обновляется из различных источников с помощью следующей команды
private void Execute_GetAgentsTickets(object agent)
{
TicketSummaries = new ObservableCollection<Ticket>();
var agentsTickets = ticketService.GetAgentsTickets((Agent)agent);
agentsTickets.ForEach(
ticket => TicketSummaries.Add(ticket)
);
AppSettings.LoggedAgent = (Agent)agent;
RequeryCommands();
}
Ноиногда эта коллекция будет изменена вне потока фоновым рабочим
void worker_TicketLoader_DoWork(object sender, DoWorkEventArgs e)
{
State = "Loading Tickets";
IsLoadingTickets = true;
var agentsTickets = ticketService.GetAgentsTickets(AppSettings.LoggedAgent);
TicketSummaries = new ObservableCollection<Ticket>();
foreach (Ticket ticket in agentsTickets)
{
TicketSummaries.AddOnUIThread<Ticket>(ticket);
}
refreshOpenTicket();
lastRefresh = DateTime.Now;
}
На всякий случай, если что-то изменится, TicketSummaries.AddOnUIThread (ticket);это решение, которое я нашел в StackOverflow, чтобы попытаться добавить элементы в коллекцию, которая является источником привязки к элементам управления пользовательского интерфейса вне потока и имеет вид:
public static void AddOnUIThread<T>(this ICollection<T> collection, T item)
{
Action<T> addMethod = collection.Add;
Application.Current.Dispatcher.BeginInvoke(addMethod, item);
}
Надеюсь, это поможет пролить немного света на ситуацию,Еще раз спасибо за ваше время.