在创建对象的线程上调用方法

时间:2010-12-22 19:11:24

标签: c# multithreading events

假设我在线程T上创建了一个对象O.如何从对象O内部获取线程T并在该线程上调用一个方法?这样,创建对象的表单就不需要这样:

    private void ChangeProgress(int value)
    {
        progressBar1.Value = value;
    }

    void FD_ProgressChanged(object sender, DownloadEventArgs e)
    {
        if (InvokeRequired)
        {
            Invoke(new Action<int>(ChangeProgress), new object[] { e.PercentDone });
        }
        else ChangeProgress(e.PercentDone);
    }

这只是丑陋的并且要求使用该对象的任何人要么弄清楚在创建该对象的同一个线程上引发了哪些事件,哪些不是,并在那些不是的那些上添加if(InvokeRequired)...else代码,或者只需在每个事件处理程序上添加代码。如果对象本身负责在正确的线程上调用事件,我认为会更优雅。这可能吗?

4 个答案:

答案 0 :(得分:4)

使用BackgroundWorker类。它负责所有这些。请注意ReportProgress事件。

答案 1 :(得分:2)

您必须自己跟踪

class Foo {
    private readonly Thread creatingThread;

    public Foo() {
        this.creatingThread = Thread.CurrentThread;
    }
}

如果你不这样做,就没有办法知道。但你这样做的事实是一种气味。考虑使用BackgroundWorker

答案 2 :(得分:1)

您需要考虑以下几点:

  • 您需要在创建它的线程的Object O中保留引用。可能在使用Thread.Current静态属性的构造函数中。
  • 该主题需要与SynchronizationContext相关联。 (通常,UI线程拥有它。并且为您创建的自定义线程创建一个并不容易。)
  • 要在该线程上调用方法,您需要在该线程的Send()上使用Post()SynchronizationContext方法。

答案 3 :(得分:1)

http://www.codeproject.com/KB/threads/invoke_other_way.aspx

找到了一个不错的解决方案

这是我的通用版本:

    private void RaiseEventAsync(Delegate handler, object e)
    {
        if (null != handler)
        {
            List<Delegate> invocationList = handler.GetInvocationList().ToList();

            foreach (Delegate singleCast in invocationList)
            {
                System.ComponentModel.ISynchronizeInvoke syncInvoke =
                           singleCast.Target as System.ComponentModel.ISynchronizeInvoke;
                try
                {
                    if ((null != syncInvoke) && (syncInvoke.InvokeRequired))
                        syncInvoke.Invoke(singleCast,
                                      new object[] { this, e });
                    else
                        singleCast.Method.Invoke(singleCast.Target, new object[] { this, e });
                }
                catch
                { }
            }
        }
    }

这就是你如何使用它:

    protected void OnProgressChanged(DownloadEventArgs e)
    {
        RaiseEventAsync(ProgressChanged, e);
    }

这样可以解决我的问题,而不需要使用并不总是需要的BackgroundWorker(就像我的情况一样,我正在为已经使用不同线程对象的类创建子类)。