.net - 使用事件获取在单独线程上运行的任务的用户输入
问题描述
我有一个长时间运行的任务,它在一个单独的线程中运行。此方法使用 IProgress 报告进度条。这种方法有很多地方需要用户输入(数据冲突)。发生这种情况时,我正在使用事件(仅摘录),并修改 eventargs 以传达结果。
string taskResult = await Task.Run(() =>
{
cpCloneManager cloner = new cpCloneManager(_progress.ReportProgress, srcProvider, srcProjectID, destProvider, destProjectID, transferType);
cloner.SynchConflict += Cloner_SynchConflict;
cloner.CloneProject(destSubscriberId, hsTypesToCopy, true);
}
private void Cloner_SynchConflict(object sender, SyncConflictEventArgs e)
{
if (_progress.IsSplashFormVisible) _progress.CloseWaitForm();
if (e.SrcObject is Role) ResolveRoleConflict(e);
if (e.SrcObject is Project) throw new ApplicationException("There is already an existing project in the target database created from the source project.");
if (!_progress.IsSplashFormVisible)
{
_progress.ShowWaitForm(mx);
}
}
void ResolveRoleConflict(SyncConflictEventArgs e)
{
if (e.DestObject == null) return;
using (popRoleConflictDialog pRCD = new popRoleConflictDialog(e))
{
if (pRCD.ShowDialog() == DialogResult.Cancel)
{
setStatusResubmit();
e.Cancel = true;
}
}
}
public class cpCloneManager : IDisposable
{
public event EventHandler<SyncConflictEventArgs> SynchConflict;
public virtual void OnSynchConflict(SyncConflictEventArgs e) => SynchConflict.Invoke(this, e);
public cpCloneManager(IProgress<(ProgressFormCommandEnum, int, string)> Progress, DatabaseProvider srcDbProvider, int SrcProjectID, DatabaseProvider destDbProvider, int DestProjectID, CloneTransferType CopyType)
{
//...
}
public string CloneProject(int TargetSubscriberId, HashSet<Type> HsTypesToClone = null, bool AddAsNew = false)
{
//...
var e_synch = new SyncConflictEventArgs(p_src, p_dest, dest_subscriberId);
OnSynchConflict(e_synch);
if (e_synch.result = Result.Copy)
{
//...
}
}
}
这通常可以正常工作,但是一些用户在渲染我用来获取用户反馈的 winform 时遇到了奇怪的效果。这与显示用户反馈表单的上下文有关。表单实际上是 devexpress winform,因此不确定问题出在 winform 本身还是 devex 皮肤上,但无论哪种方式都需要对其进行排序。
我已经查看了针对此要求的其他解决方案,包括 如何暂停在工作线程上运行的任务并等待用户输入?,但这需要大量的重构并且会更加冗长。
我的问题是:
- 使用事件来获取此反馈是否是一个可行的解决方案,如果是,我如何确保我的表单可靠呈现?
- 如果此解决方案(事件)存在无法克服的问题,那么解决此问题的最佳方法是什么?一个例子将不胜感激。
解决方案
我假设,Cloner_SynchConflict
是表单中的一种方法。尝试将其更改为:
private void Cloner_SynchConflict(object sender, SyncConflictEventArgs e)
{
if (InvokeRequired)
{
Invoke((EventHandler<SyncConflictEventArgs>)Cloner_SynchConflict, sender, e);
return;
}
if (_progress.IsSplashFormVisible) _progress.CloseWaitForm();
if (e.SrcObject is Role) ResolveRoleConflict(e);
if (e.SrcObject is Project) throw new ApplicationException("There is already an existing project in the target database created from the source project.");
if (!_progress.IsSplashFormVisible)
{
_progress.ShowWaitForm(mx);
}
}
你在这里并不需要一个事件,一个简单的回调函数也可以。类似于 a 的东西Func<[Types used in SyncConflictEventArgs], bool>
,您将其传递给您的 cpCloneManager 构造函数。无论如何,您应该将调用同步回 UI 线程。该类Progress<T>
自动执行此操作(通过SyncronizationContext
在构造函数中使用咳嗽)。
推荐阅读
- javascript - 代理在以下上下文中的含义是什么?正如我在 Javascript MDN 中发现的那样
- python - 如何使用python导入路径中的所有文件
- azure - Azure Ad B2C - B2c 如何检查用户是否已登录?
- python - 使用 cython 编译代码后无法运行 pyqt5 应用程序
- linux - User.Identity.IsAuthenticated 在 ASP.NET Core 5 上使用 Apache 反向代理到 Windows 网络上的 Kestrel Razor 页面应用程序返回 false
- android - 在 AutoCompleteTextView 的下拉背景上使用插图
- java - 为什么不能使用 Mediaplayer 从下载路径播放音乐?
- powershell - 为什么 PowerShell Core 7 不能识别 UNC 路径,而 Windows PowerShell 和 cmd 可以?
- python - FileNotFoundError: [WinError 2] The system cannot find the file specified: on visual studio code
- android - Android Sceneform 无法使用 gltf 文件