【发布时间】:2014-03-11 01:35:48
【问题描述】:
所以我想在后台线程中加载我的数据集合,然后将我的树视图绑定到新集合(而不是让后台线程在每次想要将项目添加到列表时在调度程序上排队 [听起来低效])。
这可能吗?我创建了新的数据结构,它在后台线程上作为 pd.result 输出。当 UI 线程检查对话框是否已关闭时,它应该设置
ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
在此之后事件 OnLoadVCD 被调用。我有一个事件处理程序,然后尝试设置 树视图的 itemsource 到新集合。
this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
这会因错误而崩溃: “调用线程无法访问此对象,因为另一个线程拥有它。”
甚至不知道如何调试它,调用堆栈没有提供任何真实的细节。
但是,如果我只是将 Itemsource 设置为一个空白的新空集合,如下所示:
this.AvailableModulesTreeView.ItemsSource = (IEnumerable<object>)new List<object>();
它不会崩溃(但它也不会显示我的数据)。任何想法可能导致崩溃?
我认为可能是我从错误的线程更新 UI,所以我尝试使用 begininvoke 调用调度程序,并使用 dispatcher.checkaccess() 检查我确实是 UI 线程。所以这似乎不是问题。但是,我真的不知道发生了什么。
我可以实现的另一种方法是让我的解析例程只更新绑定到树视图的原始数据结构,方法是在添加到可观察集合时在每个项目上调用调度程序。但是,即使这是唯一的解决方案,我也真的不喜欢不知道为什么某些东西不起作用。在我看来,在不同的线程上创建一个全新的数据结构,然后将新的数据结构重新绑定到树视图,丢弃旧的数据结构似乎是合理的。在我看来,它也比几十个 1 行 ObservableCollectionInstance 更干净。在后台线程上解析文件时,添加调用被放置在调度程序上。
完整代码:
UI线程调用的方法
public bool LoadPortInterface(string VCDFileName)
{
ProgressDialog pd = new ProgressDialog("Loading File: ", VCDFileName);
pd.Owner = Application.Current.MainWindow;
pd.WindowStartupLocation = WindowStartupLocation.CenterOwner;
ModuleHierarchyVM.TopLevelModules.Clear();
VCDData TempVCDOutput = null;
Func<object> handler = delegate
{
return VCDParser.ParseVCDFileForAllPorts(VCDFileName, this, pd.Worker, out TempVCDOutput);
};
pd.RunWorkerThread(handler);
pd.ShowDialog();
if (pd.DialogResult == true)
{
ModuleHierarchyVM.TopLevelModules = pd.Result as ObservableCollection<ModuleViewModel>;
VCDOutput = TempVCDOutput;
}
OnLoadVcd();
}
在 graphviewer 中对 OnLoadVCD 事件处理程序的响应:
void gvvm_LoadVCDEvent(object sender, EventArgs e)
{
this.AvailableModulesTreeView.ItemsSource = gvvm.ModuleHierarchyVM.TopLevelModules;
}
【问题讨论】:
-
您将
this传递给解析器。我认为我们需要看看该代码中发生了什么。可以发一下吗? -
我很确定我找到了真正的问题。我试图在可观察的集合上调用 OnPropertyChanged。我猜我试图处理我的集合视图源而不是通过强制它来更新。但我不明白为什么它适用于一个案例而不会崩溃。无论如何,现在我只需要弄清楚我实际上应该做什么。一种选择是将新创建的 Observable 集合重新绑定到我在 xaml 中定义的 collectionviewsource。或者我可以将集合传递给后台线程,但让任何视图模型更新都由 WPF 调度程序调度。我敢打赌前者更容易
-
为什么不让解析器返回一个List
,然后在返回时在UI线程中添加一个新的ObservableCollection?是否需要是后台线程中的 ObservableCollection? -
不,我会试试看是否有帮助。我认为问题可能出在我的 collectionviewsource 上。是否无法更新 UI 正在使用的 collectionviewsource 的源?
-
没有理由不为 TopLevelModules 对象本身调用 NotifyPropertyChanged - 这应该会触发 UI 重新加载整个集合而没有问题。
标签: c# wpf backgroundworker