Acessando os membros da classe com invocar de um tópico diferente em C#
-
23-08-2019 - |
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.
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();
}
}