早上好,
为即将提供的大量文字道歉但......
我有一个WPF ListView,其ItemsSource绑定到它的各自ViewModel中的ObservableCollection。加载窗口时,可通过命令从Web服务填充可观察集合。但是,在程序运行时,BackgroundWorker线程会定期更新此集合,以便向ObservableCollection添加新项目。
这种机制很好用。在UI线程和后台线程上更新ListView没有问题。但是,当双击ListView中的项目时,将打开一个新窗口以显示上述ObservableCollection中包含的Ticket对象的详细信息。
我有一个私有方法,每次调用ObservableCollection的set方法时都会触发该方法,该方法用于从新窗口中打开的集合中查找Ticket项,并根据新更新的ObservableCollection中的项更新其属性。在进行此更新之前,我检查以确保ObservableCollection.Count大于1,如果没有要更新的内容,没有必要进行更新!
我的问题是ObservableCollection.Count属性总是等于0.但我知道这不是真的,因为ListView仍在使用添加到此集合的新Ticket对象更新其项目,如果此集合的计数确实是0,然后这将由ListView反映,其中没有任何项目,因为它绑定到此集合。
那么这里发生了什么?我想知道可能是因为BackgroundWorker正在调用;
myCollection = new ObservableCollection();
在与UI不同的线程上,当我检查UI线程上的计数时,错误的集合对象实际上是针对'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集合,以及用于更新子视图模型中Ticket属性的refreshOpenTicket()方法,该模型是新刷新集合中的新实例。
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上发现的一个解决方案,试图将项添加到集合中,该集合是线程外UI控件的绑定源,并且是;
public static void AddOnUIThread<T>(this ICollection<T> collection, T item)
{
Action<T> addMethod = collection.Add;
Application.Current.Dispatcher.BeginInvoke(addMethod, item);
}
我希望这有助于更多地了解情况。 再次感谢您的时间。
答案 0 :(得分:0)
您没有提供足够的信息来诊断,但我猜测ListView
已绑定到某个属性,当您替换ObservableCollection
时,您不会更新该属性。因此,当您的VM代码使用新代码时,ListView
仍附加到原始集合。
为什么要更换OC?为什么不在项目来自中间层时更新它?如果你真的必须更换它,请务必通过一个属性并提出该属性的更改通知。