【发布时间】:2012-02-19 13:23:14
【问题描述】:
在处理现有项目时,我必须使用 WinForms(已经有一段时间没有使用它了)并且遇到了与 UI 线程同步的问题。
我必须集成的设计如下: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();
}
有了这个,下面的代码就可以工作了:
private DialogResult ShowDialog(Form form)
{
DialogResult dialogResult = DialogResult.None;
Action action = delegate { dialogResult = form.ShowDialog(); };
form.Invoke(action);
return dialogResult;
}
对于本示例,启动位置已设置为 windows 默认值。
如果我将其更改为:
Action action = delegate { dialogResult = form.ShowDialog(ParentWindow); };
其中ParentWindow 是IWin32Window 的一个实例,WindowStartupLocation 设置为CenterParent。调用 form.Invoke(action) 时出现跨线程异常。
跨线程操作无效:控件“ActivationConfirmationForm”从创建它的线程以外的线程访问。
问题:
- 为什么只有将启动位置设置为
CenterParent时才会出现跨线程异常?我该如何避免呢? - 为什么
form.InvokeRequired总是false?
两者可能是相关的!?
[编辑] @雷纽兹: 你不会在这里错过任何东西;) 呼叫是由核心通知的侦听器发出的
private static void OnActivationConfirmationRequired(DmsPackageConfiguratorCore sender,
ConfigurationActivationConfirmationEventArgs args)
{
args.DoAbort = (ShowDialog(new ActivationConfirmationForm(args.Data)) == DialogResult.No);
}
我可以使用的一切都在 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; }
}
【问题讨论】:
-
是因为
CenterParent还是因为您实际上正在设置父窗口而触发跨线程异常(即,如果您删除CenterParent设置,它仍然会触发吗)? -
@Strillo 在设置 ParentWindow 时总是会触发
-
表单调用来显示自己?或者我在这里遗漏了什么?你能发布所有代码吗?
-
@Reniuz 我已经在帖子本身中添加了答案(出于格式原因......)
-
我认为问题可能是您试图访问一个没有句柄的窗口(ParentWindow)。如果您尝试公开父窗口的
CreateHandle方法,然后在构造函数中或执行操作之前在子代码中调用它怎么办?
标签: c# winforms multithreading