Pergunta

Observação: Parte de uma série: C#: acessando membros do formulário de outra classe e Como acessar os objetos de formulário de outro arquivo CS em C#.


Olá,

A idéia é notificar o usuário usando o memorando quando um pacote é recebido/enviado em um cliente TCP.

Após algumas correções, a solução mais adequada parecia ser essa

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

É assim que está sendo chamado

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

No entanto, chamar o código lança uma exceção, devido à chamada de thread insegura. Encontrei uma solução em msdn, mas não consigo adquirir o método que eles usaram lá.

Este é o meu remake, o que não funciona.

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

erros:

Argumento '1': não é possível converter de 'grupo de métodos' para 'System.delegate'

Argumento '2': não é possível converter de 'string' para 'objeto []'

Basicamente, estou tentando acessar o memorando (ou é mais provável que tenha dito, adicione texto ao memorando) de outro tópico usando Invoke. Eu nunca o usei antes, talvez seja por isso que entendi mal meu erro.

Foi útil?

Solução

A maneira mais fácil é:

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

Que usa um método anônimo para fazer o trabalho em linha. Desde que você Espero Para estar em outro tópico, você também pode chamar Invoke - ele é seguro mesmo do tópico da interface do usuário.

Outras dicas

Se você estiver usando C# 3.0 e a estrutura 3.5, tente o seguinte

if ( this.Memo.InvokeRequired ) {
  this.Invoke((Action)(() => SetTextMemo(txt)));
} 

Sua implementação pressupõe que o método não se repetirá infinitamente porque o comportamento da propriedade Invokerequired o impedirá. Essa suposição pode ser verdadeira, mas não há problema em codificar a função para evitar completamente essa possibilidade. Aqui está o que sugiro:

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

    private delegate void MemoSetter(string txt);

    public void ThreadSafeSet(string txt)
    {
        Invoke(new MemoSetter(SetMemo), txt);
    }

Eu costumava lidar com todo esse negócio de fibras cruzadas, mas recentemente fui com a AOP, onde você simplesmente decora um método para executar no tópico da interface do usuário. Aqui está um exemplo (de 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();
  }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top