Phi*_*ppe 10 c# multithreading winforms
在现有项目上工作,我必须使用WinForms(暂时没有使用它)并且遇到与UI线程同步的问题.
我必须集成的设计如下:A BackgroundWorker获取Action一个参数并异步执行它.我正在采取的行动有两个部分; 核心类(包含业务逻辑)和GUI部分,如果必须请求用户交互,则由核心通过事件通知.
我已经将句柄创建添加到表单的构造函数中
if (!IsHandleCreated)
{
//be sure to create the handle in the constructor
//to allow synchronization with th GUI thread
//when using Show() or ShowDialog()
CreateHandle();
}
Run Code Online (Sandbox Code Playgroud)
有了这个,下面的代码工作:
private DialogResult ShowDialog(Form form)
{
DialogResult dialogResult = DialogResult.None;
Action action = delegate { dialogResult = form.ShowDialog(); };
form.Invoke(action);
return dialogResult;
}
Run Code Online (Sandbox Code Playgroud)
对于此示例,启动位置已设置为Windows默认值.
如果我将其更改为:
Action action = delegate { dialogResult = form.ShowDialog(ParentWindow); };
Run Code Online (Sandbox Code Playgroud)
哪里ParentWindow是实例IWin32Window和WindowStartupLocation设置为CenterParent.调用时遇到跨线程异常form.Invoke(action).
跨线程操作无效:控制从其创建的线程以外的线程访问的"ActivationConfirmationForm".
问题:
CenterParent?我该如何避免呢?form.InvokeRequired总是为什么false?两者都可能有关系!?
[编辑] @Reniuz:你在这里没有遗漏任何东西;)这个电话来自一个被核心通知的听众
private static void OnActivationConfirmationRequired(DmsPackageConfiguratorCore sender,
ConfigurationActivationConfirmationEventArgs args)
{
args.DoAbort = (ShowDialog(new ActivationConfirmationForm(args.Data)) == DialogResult.No);
}
Run Code Online (Sandbox Code Playgroud)
我可以使用的一切都在GUI界面中
/// <summary>
/// Interface defining methods and properties used to show dialogs while performing package specific operations
/// </summary>
public interface IPackageConfiguratorGui
{
/// <summary>
/// Gets or sets the package configurator core.
/// </summary>
/// <value>The package configurator core.</value>
IPackageConfiguratorCore PackageConfiguratorCore { get; set; }
/// <summary>
/// Gets or sets the parent window.
/// </summary>
/// <value>The parent window.</value>
IWin32Window ParentWindow { get; set; }
/// <summary>
/// Gets the package identifier.
/// </summary>
/// <value>The package identifier.</value>
PackageIdentifier PackageIdentifier { get; }
}
Run Code Online (Sandbox Code Playgroud)
看到 form.InvokeRequired 为false是问题的核心。你知道这一定是真的。简单的解释是传递给 ShowDialog() 方法的表单对象是错误的对象。典型的错误是使用new来创建实例,而不是使用表单对象的现有实例(用户正在查看并在主线程上创建的实例)。确保线程代码具有对该表单对象的引用,以便它可以传递正确的引用。仅当您无法正确使用时才使用 Application.OpenForms[0]。
一般来说,将线程代码与用户界面分离。工作线程不需要显示对话框。你可以让它发挥作用,但在实践中效果不佳。该对话框在用户没有预料到的情况下弹出。用户可能会在弹出对话框之前单击或按下某个键不到一秒,从而很可能发生意外。甚至没有看到它就关闭该对话框。同样,CreateHandle() 黑客也不应该出现在您的代码中。只是在用户界面准备好之前不要启动线程。由表单的 Load 事件发出信号。