有解决非法跨线程操作异常的方法吗?

时间:2020-03-05 18:37:41  来源:igfitidea点击:

当我们在C#中绑定数据时,更改数据的线程也会导致控件发生更改。但是,如果此线程不是在其上创建控件的线程,则会出现"非法跨线程操作"异常。

反正有防止这种情况发生的方法吗?

解决方案

回答

我们应该能够执行以下操作:

if (control.InvokeRequired)
{
    control.Invoke(delegateWithMyCode);
}
else
{
    delegateWithMyCode();
}

InvokeRequired是控件上的一个属性,以查看我们是否在正确的线程上,然后Invoke将在正确的线程上调用委托。

更新:实际上,在我的上一份工作中,我们做了这样的事情:

private void SomeEventHandler(Object someParam)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new SomeEventHandlerDelegate(SomeEventHandler), someParam);
    }

    // Regular handling code
}

这消除了对else块的需要,并加强了代码的种类。

回答

因为我没有测试用例,所以我不能保证这种解决方案,但是在我看来,类似于用于更新不同线程(使用委托)中的进度条的方案在这里适用。

public delegate void DataBindDelegate();
public DataBindDelegate BindData = new DataBindDelegate(DoDataBind);

public void DoDataBind()
{
    DataBind();
}

如果数据绑定需要由特定线程完成,则让该线程完成工作!

回答

如果数据修改不太耗时(也就是说,如果后台线程的主要目的不是实际的数据修改),请尝试将修改数据的部分移至委托中并调用该委托。

如果实际的工作量很大,则可能必须创建该数据的深层副本以传递到后台线程,该线程将再次通过Invoke将处理后的数据发送回UI线程。

我们只需要将更改数据的代码移到委托函数中(因为数据更改是触发控件更新的原因)。除此之外,我们无需额外编写任何内容。

回答

如果线程调用是"非法的"(即,DataBind调用影响到未在其中调用的线程中创建的控件),则我们需要创建一个委托,以便即使未在DataBind中完成决定/准备工作也是如此。创建控件的线程,对它们进行的任何结果修改(即DataBind())都将是。

我们可以像这样从工作线程调用我的代码:

this.BindData.Invoke();

然后,这将导致原始线程进行绑定,绑定应该工作(假定它是创建控件的线程)。

回答

在WPF和Silverlight中,绑定基础结构负责切换到UI线程。