Вызов метода для потока, который создал объект - PullRequest
2 голосов
/ 22 декабря 2010

Допустим, я создал объект O в потоке T. Как я могу получить изнутри объекта 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 ]

4 голосов
/ 22 декабря 2010

Используйте класс BackgroundWorker. Он позаботится обо всем этом. Обратите внимание на событие ReportProgress.

2 голосов
/ 22 декабря 2010

Вам придется отслеживать это самостоятельно, как

class Foo {
    private readonly Thread creatingThread;

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

Если вы этого не сделаете, вы не сможете узнать об этом.Но то, что вы делаете, это запах.Попробуйте использовать BackgroundWorker.

1 голос
/ 22 декабря 2010

Нашел хорошее решение на 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, который не всегда нужен (как в моем случае, когда я делаю подкласс класса, который уже использует другой объект потоков).

1 голос
/ 22 декабря 2010

Есть несколько вещей, которые вы должны учитывать:

  • Вам нужно будет сохранить ссылку в Object O потока, в котором он был создан. Вероятно, в конструкторе, использующем Thread.Currentстатическое свойство.
  • С этим потоком должен быть связан SynchronizationContext.(Как правило, потоки пользовательского интерфейса имеют его. И его нелегко создать для созданного вами пользовательского потока.)
  • Чтобы вызвать метод в этом потоке, вам необходимо использовать методы Send() или Post()в этой теме SynchronizationContext.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...