[编辑]已解决,见下文[/编辑]
这是一个新手问题。
我只是深入研究 C# 和异步,为什么我想要:
- 单击按钮
- 按顺序运行多个任务,但在后台线程中一个接一个地运行
- 如果可能的话,正在运行的任务应该通知它们的进度
现在我可以单击按钮并启动任务链,但在完成事件中我希望(用于测试)每次任务完成时显示一个消息框。这可能会导致崩溃(?),我不知道为什么,因为我以为我会在 ui 线程内......
这是代码的一些部分:
应用程序视图模型:
void handlePhaseCompletedEvent(object sender, SyncPhaseCompletedEventArgs e)
{
Shell.Current.DisplayAlert("TEST", "PHASE " + e.phase.ToString(), "OK"); // <<<< doesn't show up, maybe because its crashing a short time after?
syncToolService.StartSyncPhaseAsync(e.phase + 1, this); // <<<< seems to crash here?
}
[RelayCommand]
async Task StartSyncAsync()
{
syncToolService.NotifySyncPhaseCompleted += handlePhaseCompletedEvent;
syncToolService.StartSyncPhaseAsync(0, this);
}
同步工具服务:
public event EventHandler<SyncPhaseCompletedEventArgs> NotifySyncPhaseCompleted;
public async Task StartSyncPhaseAsync(int phase, AppViewModel viewModel)
{
// search for Remote-peer
if (phase == 0)
{
Task t = new Task(() => Task.Delay(100)); // dummy, not implemented yet
t.ConfigureAwait(false);
t.ContinueWith(t => NotifySyncPhaseCompleted?.Invoke(this, new SyncPhaseCompletedEventArgs { phase = phase }));
t.Start();
return;
}
// Remote Sync start preparations
if (phase == 1)
{
Task t = new Task(() => Task.Delay(100)); // dummy, not implemented yet
t.ConfigureAwait(false);
t.ContinueWith(t => NotifySyncPhaseCompleted?.Invoke(this, new SyncPhaseCompletedEventArgs { phase = phase }));
t.Start();
return;
}
//////// LOCAL PREPARATIONS
// read local files
if (phase == 2)
{
Task t = new Task(() => BPMSyncToolService.loadLocalData(viewModel.DataFiles));
t.ConfigureAwait(false);
t.ContinueWith(t => NotifySyncPhaseCompleted?.Invoke(this, new SyncPhaseCompletedEventArgs { phase = phase }));
t.Start();
return;
}
}
基本上我认为 StartSyncPhaseAsync 会运行一个任务(它似乎是这样做的)
它似乎也触发了事件(这似乎不会引发异常)
当在调试中逐行运行时,它会崩溃syncToolService.StartSyncPhaseAsync(e.phase + 1, this);
有了这个堆栈:
> [Exception] WinRT.Runtime.dll!WinRT.ExceptionHelpers.ThrowExceptionForHR.__Throw|20_0(int hr)
[Exception] Microsoft.WinUI.dll!Microsoft.UI.Xaml.Controls.ContentDialog._IContentDialogFactory.CreateInstance(object baseInterface, out System.IntPtr innerInterface)
[Exception] Microsoft.WinUI.dll!Microsoft.UI.Xaml.Controls.ContentDialog.ContentDialog()
[Exception] Microsoft.Maui.Controls.dll!Microsoft.Maui.Controls.Platform.AlertManager.AlertRequestHelper.OnAlertRequested(Microsoft.Maui.Controls.Page sender, Microsoft.Maui.Controls.Internals.AlertArguments arguments)
System.Private.CoreLib.dll!System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Private.CoreLib.dll!System.Threading.Tasks.Task.ThrowAsync.AnonymousMethod__128_1(object state)
System.Private.CoreLib.dll!System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()
System.Private.CoreLib.dll!System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
我的设计中也可能存在一般问题,任何帮助都会很棒!
[UPDATE]它现在按预期运行。
新手想法:
- 来自 ToolmakerSteve 的回答https://stackoverflow.com/a/73409415/4232410 https://stackoverflow.com/a/73409415/4232410我想“嘿,但这就是我首先尝试的,它锁定了用户界面”。然后我看了 and https://www.youtube.com/watch?v=ZTKGRJy5P2M https://www.youtube.com/watch?v=ZTKGRJy5P2M我看到“嘿,这基本上就是上面提到的,而且它有效,所以我的错在哪里(现在当我写这篇文章时,我看到了他的妻子,非常感谢!)
- Ryan 提到了“ReportProgress”(这就是我偶然发现上述视频的方式),它起作用了,也谢谢你!
所以这基本上是实际的工作代码,似乎不会锁定 UI 并且不会崩溃(崩溃是因为 Microsoft.VisualBasic.FileIO.TextFieldParser 尝试读取一行并找到一个以引号开头的字段并认为它将是一个封闭的引用,但事实并非如此)
应用程序视图模型:
private void HandleSyncProgressChanged(object sender, SyncStatus e)
{
NumFilesProcessed = e.filesProcessed;
NumFilesNotFound = e.filesNotFound;
AktueleAufgabe = e.workingPhase;
}
[RelayCommand]
async Task StartSyncAsync()
{
Progress<SyncStatus> progress=new Progress<SyncStatus>();
progress.ProgressChanged += HandleSyncProgressChanged;
await BPMSyncToolService.StartSyncPhaseAsync(this, progress);
}
同步工具服务:
public static async Task StartSyncPhaseAsync(AppViewModel viewModel, IProgress<SyncStatus> progress)
{
SyncStatus report = new SyncStatus();
report.workingPhase = "Suche Synchronisationspartner";
progress.Report(report);
// search for Remote-peer
await Task.Delay(100); // dummy, not implemented yet
report.workingPhase = "Starte Vorbereitungen beim Synchronisationspartner";
progress.Report(report);
// Remote Sync start preparations
await Task.Delay(100); // dummy, not implemented yet
//////// LOCAL PREPARATIONS
report.workingPhase = "lese lokale Dateien";
progress.Report(report);
// read local files
await BPMSyncToolService.LoadLocalDataAsync(viewModel.DataFiles, progress, report);
// [...]
}
我实际上看不到的是已处理文件的计数,也许它太快了,不知道,将在需要更多时间的进一步任务中看到
无论如何,谢谢,两个答案都有帮助,我将把其中一个标记为解决方案,这更接近核心问题(我认为)