Domanda

Nota:Parte di una serie: C#:Accesso ai membri del modulo da un'altra classe E Come accedere agli oggetti del modulo da un altro file CS in C#.


Ciao,

L'idea è di notificare all'utente utilizzando il promemoria quando un pacchetto viene ricevuto/inviato in un client TCP.

Dopo un paio di correzioni, la soluzione più adatta sembrava essere questa

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

È così che viene chiamato

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

Tuttavia, la chiamata al codice genera un'eccezione, a causa della chiamata al thread non sicuro. Ho trovato una soluzione su msdn,ma non riesco ad acquisire il metodo che hanno usato lì.

Questo è il mio remake, che non funziona.

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

errori:

Argomento '1':impossibile convertire da "gruppo di metodi" a "System.Delegate"

Argomento '2':impossibile convertire da "stringa" a "oggetto[]"

Fondamentalmente, sto cercando di accedere al Memo (o, più probabilmente, di aggiungere testo al memo) da un altro thread utilizzando Invoke. Non l'ho mai usato prima, forse è per questo che ho frainteso il mio errore.

È stato utile?

Soluzione

Il modo più semplice è:

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

Che utilizza un metodo anonimo per svolgere il lavoro in linea.Dato che tu aspettarsi per essere su un altro thread, puoi anche chiamare Invoke: è sicuro anche dal thread dell'interfaccia utente.

Altri suggerimenti

Se usi C# 3.0 e il framework 3.5, prova quanto segue

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

L'implementazione presuppone che il metodo non ricorra all'infinito perché il comportamento della proprietà InvokeRequired lo impedirà.Questo presupposto potrebbe rivelarsi vero, ma non ci sono problemi a codificare la funzione per evitare completamente questa possibilità.Ecco cosa suggerisco:

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

    private delegate void MemoSetter(string txt);

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

In passato gestivo tutte queste attività cross-thread, ma recentemente sono andato con AOP, dove devi semplicemente decorare un metodo da eseguire sul thread dell'interfaccia utente.Ecco un esempio (da 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();
  }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top