gpt4 book ai didi

带有 UI 线程问题的 WPF - TaskFactory、CollectionView 问题 - 语法噩梦

转载 作者:行者123 更新时间:2023-12-03 13:05:11 26 4
gpt4 key购买 nike

有关我的伪解决方案,请参阅帖子底部。

我再一次完全和完全地坚持这一点。我花了好几个小时试图理解——是的,我可以让一个 collectionviewsource 完美地工作,而无需在后面的代码上进行线程处理。

想象一下,当我发现仅在页面上添加两个 collectionviewsource 会导致线程问题时,我会感到震惊。昨晚我花了几个小时阅读 C#5 中的 Async 和 MSDN 的东西,但是我今天开始工作,但我不知道如何实现这一点。

下面的代码是我在哀求帮助之前所做的最后一次尝试,因为我可能已经花费了太多的工作时间来试图理解如何做到这一点。我知道我需要一个 collectionviewsource 在开始另一个之前完成,所以我尝试了 Await Task.ContinueWith 等来尝试一个接一个地链接。

正确排列线程中的两组任务似乎非常棘手,或者我仍然误解了一些基本的东西。

如果有人能建议他们如何在 WPF UI 上异步填充一些控件,我将不胜感激。

该应用程序本身是一个一次性应用程序,链接到一个 Access 数据库,我正在使用该数据库来尝试在线程方面变得足够流利,以便在我们适当的代码库中实现它。我离那个很远!

更新了更完整的代码示例并根据答案进行了调整:

Private Async Sub MainWindowLoaded(sender As Object, e As RoutedEventArgs) Handles MyBase.Loaded
InitializeComponent()

Dim personSetViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("personSetViewSource"), System.Windows.Data.CollectionViewSource)
Dim contactSetViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("contactSetViewSource"), System.Windows.Data.CollectionViewSource)

Dim personList = Await Task.Run(Function() personSet.personList)
personSetViewSource.Source = personList

Dim contactList = Await Task.Run(Function() contactSet.contactList)
contactSetViewSource.Source = contactList

End Sub`

ObservableCollectionEx 类:
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
public override event NotifyCollectionChangedEventHandler CollectionChanged;

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
using (BlockReentrancy())
{
NotifyCollectionChangedEventHandler collectionChanged = this.CollectionChanged;
if (collectionChanged != null)
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
{
DispatcherObject dispObj = nh.Target as DispatcherObject;
if (dispObj != null)
{
Dispatcher dispatcher = dispObj.Dispatcher;
if (dispatcher != null && !dispatcher.CheckAccess())
{
NotifyCollectionChangedEventHandler nh1 = nh;
dispatcher.BeginInvoke(
(Action) (() => nh1.Invoke(this,
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset))),
DispatcherPriority.DataBind);
continue;
}
}
nh.Invoke(this, e);
}
}
}
}

请注意,由于需要事件覆盖,我无法将此类转换为 VB。
我尝试过的另一个变体,但再次违反了线程所有权。这两个 Collection View 的事情并没有产生解决方案:我不知道是不是因为底层集合不适合它,或者实际上它不应该以这种方式工作。我靠近但没有雪茄。
 Dim CarePlanList = Task.Run(Function() CarePlanSet.CarePlanList)
Dim rcpdList = Task.Run(Function() rcpdSet.rcpdList)

Dim tasks() As Task = {CarePlanList, rcpdList}
Dim t = New TaskFactory
Await t.ContinueWhenAll(tasks, Sub()
carePlanSetViewSource.Source = CarePlanList
rcpdSetViewSource.Source = rcpdList
End Sub)

根据今天早上的反馈和研究,我找到了一种方法。鉴于 WPF 的 STAThread 模型,异步构建两个 Collection View 本身有些不切实际。然而,仅仅确保一个 HAS 完成并将一些异步从一个实体类中移出就可以做到这一点。

相反,我启动了第一个任务,谁的底层类确实使用它自己的 Async 方法构建它的数据。然后在允许第二个collectionview被触发之前测试它是否已经完成。这样我就不需要担心上下文或调度程序对象。第二个集合不使用任何异步。
    Dim personList = Task(Of List(Of person)).Run(Function() personSet.personList)
Dim contactList = Task(Of ObservableCollectionEx(Of contact)).Run(Function() contactSet.contactList)

contactSetViewSource.Source = contactList.Result
If contactList.IsCompleted Then personSetViewSource.Source = personList.Result

这确实是一个概念研究的实验项目。碰巧的是,我希望以这种方式构建两个这样的列表的想法并不像所有这些那样有用,但我确实看到了能够异步编写数据密集型接口(interface)的地方可能很方便。

最佳答案

您的两个代码示例都存在立即跳出的问题。

首先你在等待task1 ,我假设后面有更多代码,但所有 task1正在做的是启动基本上是火灾并忘记操作回到 UI 线程 (Dispatcher.BeginInvoke),因此不会真正产生任何异步等待。

其次,主要问题似乎是您正在对 Task 进行大量设置。实例并用延续链接它们,但从不启动 action2 Task ,这似乎是整个链的根,因此根本没有事件。这类似于您使用 BackgroundWorker 获得的结果。从来没有RunWorkerAsync叫。

为了让它正常工作并避免让你头晕目眩,我建议首先编写整个 block 而不进行任何异步并验证所有内容是否按预期加载,但要避免 UI 锁定。 Async/Await 旨在以最小的结构更改添加到类似的代码中。使用 Task.Run与 async 和 await 一起,您可以使代码异步。

这是基本模式的一些伪代码,没有异步启动:

PersonSetList = LoadData1()
CVS1.Source = PersonSetList
ContactList = LoadData2()
CVS2.Source = ContactList

现在添加异步:
PersonSetList = await Task.Run(LoadData1())
CVS1.Source = PersonSetList
ContactList = await Task.Run(LoadData2())
CVS2.Source = ContactList

这现在要做的是启动一个任务来加载人员数据并立即从您的 WindowLoaded 方法返回,允许 UI 继续呈现。加载该数据后,它将继续到原始线程的下一行并将数据推送到 UI(这本身可能会在渲染时减慢 UI)。之后,它将对联系人数据执行相同的操作。请注意,不需要 Dispatcher,因为 await 正在返回 UI 线程以供您完成其继续。

关于带有 UI 线程问题的 WPF - TaskFactory、CollectionView 问题 - 语法噩梦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14379158/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com