3 Stimmen

Threadübergreifender Aufruf der UI-Komponente

Ist dies ein geeigneter Weg, um Thread-übergreifende Operationen zu behandeln?

Sollte ich einen neuen Eigenschaftsnamen, etwas wie "EditValueThreadSafe" verwenden, anstatt "EditValue" zu überschreiben? Ich glaube nicht, dass es ein Problem mit den Änderungen an der Implementierung von EditValue gibt, da die Basiseigenschaft unabhängig davon aufgerufen wird.

namespace MyApplication.Components
{
    using System.Windows.Forms;

    /// <summary>
    /// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class.
    /// </summary>
    public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
    {
        /// <summary>
        /// Gets or sets the edit value.
        /// </summary>
        /// <value>The edit value.</value>
        public override object EditValue
        {
            get
            {
                return base.EditValue;
            }

            set
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new MethodInvoker(delegate
                    {
                        this.SetEditValue(value);
                    }));
                }
                else
                {
                    this.SetEditValue(value);
                }
            }
        }

        /// <summary>
        /// Sets the edit value.
        /// </summary>
        /// <param name="value">The value.</param>
        private void SetEditValue(object value)
        {
            base.EditValue = value;
        }
    }
}

2voto

Charles Bretana Punkte 137391

Sie können auch an eine andere Methode delegieren, die die Arbeit erledigt, und in dieser Methode, wenn sie sich im falschen Thread befindet (BeginInvoke gibt true zurück), dieselbe Methode erneut aufrufen. Auf diese Weise entfällt die Notwendigkeit, Code zu duplizieren.

public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit    
{       
   public override object EditValue        
   {            
       get            
       {                             
            return base.EditValue;            
       }            
       set  
       {                
         SetValue(value);
       }
   }

    private void delegate SetValueDlg(object valeu);
    private void SetValue(object value)
    {
        if (this.InvokeRequired)
             this.BeginInvoke(
                 (SetValueDlg)SetValue,  // calls itself, but on correct thread
                 new object[] { value });
        else

              base.editValue = value;  

    }
}

Sie können auch die generische Klasse Action() verwenden, um die Notwendigkeit zu beseitigen, eine explizite Delegatenklasse zu erstellen...

   public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit    
{       
   public override object EditValue        
   {            
       get {  return base.EditValue;   }            
       set { SetValue(value); }
   }

   private void SetValue(object value)
   {
       if (this.InvokeRequired)
           this.BeginInvoke(
               new Action<object>(SetValue),  // calls itself, but on correct thread
               new object[] { value });
       else                
              base.editValue = value;  

   }

}

1voto

FacticiusVir Punkte 2017

Es ist Thread-sicher, ja, aber seien Sie vorsichtig, eine Eigenschaft zu überschreiben und das Verhalten grundlegend zu ändern. Das Ändern der Implentierung ist in Ordnung, aber diese Eigenschaft verhält sich jetzt ganz anders. Sie beseitigt die Möglichkeit einer bestimmten Ausnahme, führt aber eine mögliche Deadlock- oder Blockierbedingung ein, die sich auf den aufrufenden Code auswirkt.

Also ja, das ist die korrekte Verwendung von InvokeRequired & Invoke, aber ich würde empfehlen, eine separate, zweckspezifische und Thread-sichere Eigenschaft zu erstellen, die als solche bekannt gegeben wird.

0voto

M1EK Punkte 810

Meine UI-Methoden wie Ihre sehen am Ende so aus:

public void setStatusLabelText(String s)
    {
        if (footerStatusLabel.InvokeRequired) {
            StringUpdateInvokeDelegate callback = new StringUpdateInvokeDelegate(setStatusLabelText);
            this.Invoke(callback, new object[] { s });
        }
        else {
            this.footerStatusLabel.Text = s;
        }            
    }

(dies mag für .net heutzutage veraltet sein - aber der Punkt ist, dass man die Operation einfach innerhalb dieser Methode durchführen kann, wenn man sich bereits im richtigen Thread befindet - das macht es ein wenig weniger irritierend zu lesen, aber immer noch ärgerlich im Vergleich zu Java, IMO).

0voto

csharptest.net Punkte 58070

Ich werde hier meine 2 Cent beisteuern. Die eigentlichen Aufrufe von InvokeRequired/BeginInvoke/Invoke sind nicht völlig thread-sicher. (siehe Vermeidung der Probleme von Invoke/BeginInvoke bei der threadübergreifenden WinForm-Ereignisbehandlung? ) Ich würde empfehlen, einen Weg zu finden, um die Aufrufe an diese in einem einzigen Ort, Dienstprogramm api, Erweiterung Methode oder dergleichen zu isolieren. In dem Artikel oben gibt es vollständigen Code für eine Klasse, die einen Delegaten umhüllt, um Thread-sicheres Verhalten bereitzustellen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X