c# – 将工作人员与UI线程同步

前端之家收集整理的这篇文章主要介绍了c# – 将工作人员与UI线程同步前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在现有的项目中,我必须使用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)时,我得到一个跨线程异常.

Cross-thread operation not valid: Control ‘ActivationConfirmationForm’ accessed from a thread other than the thread it was created on.

问题:

>为什么只有在将启动位置设置为CenterParent时,才会出现跨线程异常?我该如何避免呢?
>为什么form.Invokerequired总是假的?

两者都可能相关!

[编辑]
@Reniuz:
你没有在这里丢失任何东西;)
该呼叫正在由核心通知的听众进行

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; }
}

解决方法

看到form.Invokerequired在false是你的问题的核心.你知道它必须是真实的.简单的解释是传递给您的ShowDialog()方法的表单对象是错误的对象.经典的错误是使用new来创建实例,而不是使用窗体对象的现有实例,即用户正在查看并在主线程上创建的实例.确保线程代码具有对该表单对象的引用,以便它可以传递正确的引用.只有使用Application.OpenForms [0],如果你不能正确的话.

一般来说,将线程代码用户界面分离.工作线程没有显示对话的业务.你可以使它工作,但它在实践中不能很好地工作.弹出对话框,无需用户期待.发生事故可能,用户可能会在弹出对话框之前点击或按下键几分之一秒.关闭对话框,甚至不看它. CreateHandle()hack同样不应该在您的代码中.只需在用户界面准备好之前不要启动线程.由表单的Load事件发出信号.

原文链接:https://www.f2er.com/csharp/93630.html

猜你在找的C#相关文章