Доступ к членам класса с помощью Invoke из другого потока в C # - PullRequest
2 голосов
/ 04 апреля 2009

Примечание : часть серии: C #: доступ к членам формы из другого класса и Как получить доступ к объектам формы из другого файла cs в C # .


Hello

Идея состоит в том, чтобы уведомить пользователя с помощью памятки, когда пакет получен / отправлен в клиенте TCP.

После нескольких исправлений наиболее подходящим решением, похоже, было это

    public string TextValue
    {
        set
        {
            this.Memo.Text += value + "\n";
        }
    }

Вот как это называется

    var form = Form.ActiveForm as Form1;
    if(form != null)
        form.TextValue = "Test asdasd";

Однако при вызове кода возникает исключение из-за небезопасного вызова потока. Я нашел решение в msdn , но я не могу понять, какой метод они там использовали.

Это мой римейк, который не работает.

    private void SetTextMemo(string txt)
    {
        if(this.Memo.InvokeRequired)
        {
            this.Invoke(SetTextMemo,txt); //error here
        }
        else
        {
            this.Memo.Text += txt + "\n";
        }
    }

ошибка:

Аргумент '1': невозможно преобразовать из 'группы методов' в 'System.Delegate'

Аргумент '2': невозможно преобразовать из 'строки' в 'объект []'

По сути, я пытаюсь получить доступ к заметке (или, скорее, сказал, добавить текст к заметке) из другого потока, используя Invoke. Я никогда не использовал его раньше, может быть, поэтому я неправильно понимаю свою ошибку.

Ответы [ 4 ]

11 голосов
/ 04 апреля 2009

Простой способ:

this.Invoke((MethodInvoker)delegate {
    this.Memo.Text += txt + "\n";
});

Который использует анонимный метод для выполнения работы в строке. Поскольку вы ожидаете, что будет в другом потоке, вы можете просто вызвать Invoke - это безопасно даже из потока пользовательского интерфейса.

1 голос
/ 04 апреля 2009

Ваша реализация предполагает, что метод не будет бесконечно повторяться, потому что поведение свойства InvokeRequired будет препятствовать этому. Это предположение может оказаться верным, но нет проблем с кодированием функции, чтобы полностью избежать этой возможности. Вот что я предлагаю:

    private void SetMemo(string txt)
    {
        Memo.Text = txt;
    }

    private delegate void MemoSetter(string txt);

    public void ThreadSafeSet(string txt)
    {
        Invoke(new MemoSetter(SetMemo), txt);
    }
1 голос
/ 04 апреля 2009

Если вы используете C # 3.0 и платформу 3.5, попробуйте следующее

if ( this.Memo.InvokeRequired ) {
  this.Invoke((Action)(() => SetTextMemo(txt)));
} 
0 голосов
/ 04 апреля 2009

Раньше я занимался всем этим многопоточным бизнесом, но недавно я пошел с AOP, где вы просто декорировали метод для выполнения в потоке пользовательского интерфейса. Вот пример (из PostSharp):

public class FormsThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    Form f = (Form)eventArgs.Delegate.Target;
    if (f.InvokeRequired)
      f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray());
    else
      eventArgs.Proceed();
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...