2009-09-04 28 views
5

Olası Çoğalt:
Getting Cross-thread operation not valid
Cross-thread operation not validÇapraz iplik operasyonu geçerli değil

Ben yeni bir işleyici oluşturmak, böylece COM portu dinlemeye çalışıyorum SerialPort.DataReceived olayı için. Mantık basit - Ben TextBox1 bir şey yazmak, Button1 tuşuna basın ve metin Label1 içinde kendini göstermelidir. Ama benim uygulama çalıştırmak istemiyorum, 'Çapraz iş parçacığı işlemi geçerli değil' hatası atıyor. Bazı arama yaptım ve Invoke nesnesini buldum - örneğimde nasıl kullanabilirim? Neden Invoke mantığını dahil etmem gerekiyor?

namespace WindowsApplication1 
{ 
public partial class Form1 : Form 
{ 
    SerialPort sp = new SerialPort(); 

    public Form1() 
    { 
     InitializeComponent(); 
     sp.DataReceived += MyDataReceivedHandler; 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 

    } 

    private void MyDataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
    { 
     try 
     { 
      //sp.PortName = "COM3"; 
      //sp.Open(); 
      Label1.Text = sp.ReadLine(); 
     } 
     catch (Exception exception) 
     { 
      RichTextBox1.Text = exception.Message + "\n\n" + exception.Data; 
     } 
     finally 
     { 
      sp.Close(); 
     } 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      sp.PortName = "COM3"; 
      sp.Open(); 
      sp.WriteLine(TextBox1.Text); 
     } 
     catch (Exception exception) 
     { 
      RichTextBox1.Text = exception.Message + "\n\n" + exception.Data; 
     } 
     finally 
     { 
      sp.Close(); 
     } 
    } 
} 

}

+0

@ Peter: COM bağlantı noktası burada RS232 seri arabirimidir. USB'ye ve buna rağmen, PC iletişimi için seri bağlantı noktasını kullanan bir dizi aygıt (ör. GPS, Medikal) bulunmaktadır. – Sesh

+0

@_simon_: Sadece meraklı: Bu uygulamada kullanılan COM portu nedir? –

+0

@_simon_: Cevabımı güncelledim –

cevap

17

Benim tahminim MyDataReceivedHandler GUI daha farklı bir iş parçacığı üzerinde çalıştığı olmasıdır. Bunu düzeltmek için, doğru iş parçacığı üzerinde Text ayarlayıcılarını çağırmanız gerekir. Bu sayede bir örneğidir:

private delegate void SetControlTextHandler(Control control, string text); 

public void SetControlText(Control control, string text) 
{ 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new SetControlTextHandler(SetControlText), new object[] { control, text }); 
    } 
    else 
    { 
     control.Text = text; 
    } 
} 

:

public void SetControlText(Control control, string text) 
{ 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new Action<Control,string>(SetControlText), new object[] { control, text }); 
    } 
    else 
    { 
     control.Text = text; 
    } 
} 

private void MyDataReceivedHandler(object sender, SerialDataReceivedEventArgs e) 
{ 
    try 
    { 
     //sp.PortName = "COM3"; 
     //sp.Open(); 
     SetControlText(Label1, sp.ReadLine()); 
    } 
    catch (Exception exception) 
    { 
     SetControlText(RichTextBox1, exception.Message + "\n\n" + exception.Data); 
    } 
    finally 
    { 
     sp.Close(); 
    } 
} 

.NET Framework 2.0 kullanıyorsanız kendi biri tanımlamak zorunda kalacak, böylece yukarıdaki Action<T1, T2> temsilci, kullanılamaz SetControlText yöntem (bu, hem 2.0 ve 3.5 çalışır) böyle kısa (ve hatta statik) yapılabilir:

public static void SetControlText(Control control, string text) 
{ 
    ´control.Invoke((MethodInvoker)delegate { control.Text = text; }); 
} 

Sonraait denetimi yapmak gerekmezher seferinde, ancak diğer yandan, gerekmediğinde bile çağrıyı bir temsilci ile paylaşacaksınız. Bunun gibi bir GUI yönteminde, bu ikisi arasındaki herhangi bir performans farkının göz ardı edilemez olduğunu düşünüyorum, bu yüzden daha az biçim kullanmak eğilimindeyim.

+0

Görünüşe göre bu sadece 3.5'de çalışıyor. Visual studio 2005 kullanıyorum, şimdi 3.5 SP1'i kurdum. Visual Studio 2005'te hangi .NET frameworkünü kullanıyorum? – sventevit

+0

@_simon_: Yanıtı, 2.0 uyumlu sürümleri –

+0

ile güncelledim. Not: Yetkilendirilen işlemde gerçekleştirilen işlem uzun sürüyorsa, UI iş parçacığının işlemi işlemesine neden olacak şekilde, kullanıcı arabirimi hala engelleyebilir.BeginInvoke'u uygulayan tüm denetimlerde kullanmak, işlemi engellemeden, senkronize olmayan bir şekilde gerçekleştirir. –

0

Ayrıca yapabildiği tek şey üzerinde oluşturulduğu olandan farklı bir iş parçacığı bir arayüzü kontrolünü erişen her aşağıdadır:

(NET 3,5)

myControl.BeginInvoke(new MethodInvoker(() => myControl.whatever = whatever;)); 

veya (NET 2.0)

myControl.BeginInvoke(new MethodInvoker(delegate { myControl.whatever = whatever;)); 

edit> Bazen/hala Beginınvoke besbelli uyumsuz bu işlemi gerçekleştiren kullanarak, ui askıda olabilir, uzun süren bir operasyon için Invoke kullanarak, bir d ui asmayacak.

İlgili konular