Cross-thread operation not valid!

.NET kullanan yazılımcı arkadaşlar uygulama geliştirirken zaman zaman aşağıdakine benzer bir hata alabilirsiniz;

Cross-thread operation not valid: Control ‘xxxxx’ accessed from a thread other than the thread it was created on.

Bu istisnai durum herhangi bir kontrole ya da kontrolün özelliklerine, kontrolün oluşturulduğu Thread dışında farklı bir Thread üzerinden erişmeye çalışıldığında ortaya çıkıyor. Dolayısıyla bu durum daha çok Multi-Threading gerektiren uygulamalarda karşımıza çıkıyor. Peki bu sorunu nasıl çözeceğiz? İşte bu noktada .NET’in güçlü yapılarından Delegate (Temsilci) lere başvuracağız. Bu sorunu ortadan kaldırmak Delegate’ler ile inanılmaz kolay. Nasıl mı? Şöyle, bir örnekle açıklayalım;

delegate void updateLabelTextDelegate(string newText);
private void updateLabelText(string newText)
{
if (label1.InvokeRequired)
{
// worker thread
updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
label1.Invoke(del, new object[] { newText });
}
else
{
// UI thread
label1.Text = newText;
}
}

burada yapmak istediğimiz şey, uygulamamızın içerisinde bulunan Label1 adlı Label kontrolünün
Text özelliğine farklı Thread’ ler üzerinde de erişebilmek. Öncelikle ilgili kontrolün Text özelliğini değiştiren bir metodu temsil edene bir temsilci tanımlamak (ve tabii ki metodu da). İşte bu amaçla updateLabelTextDelegate adlı, uygulama içerisinde updateLabelText() metodunu temsil edebilecek bir temsilci tanımlıyoruz. Metodumuzun içerisinde ise, ilgili kontrolün eğer faklı bir Thread üzerinden erişilmişse ayrı bir invocation gerektirip gerektirmediğini kontrol ediyoruz. Artık updateLabelText() metodunu gönül rahatlığı ile uygumamızın herhangi bir yerinde, herhangi bir Thread içerisinde çağırabiliriz. Hepsi bu kadar kolay 🙂

Hepsi bu kadar 🙂

, ,

15 Responses to Cross-thread operation not valid!

  1. Süleyman 14 Ağustos 2009 at 10:19 AM #

    Bunu çözmek için neler denememiştim. Çok yararlı bir yazı olmuş teşekkürler.

  2. @bütün 14 Ağustos 2009 at 10:35 AM #

    İşine yaradığına çok sevindim Süleyman 🙂 yorumun için da ayrıca çok teşekkürler

  3. caner 13 Şubat 2010 at 1:06 AM #

    Hocam gerçekten çok süper bir yazı türkçe kaynak yok sıfır.Ellerine sağlık…

    • @bütün 16 Şubat 2010 at 10:36 AM #

      Rica ederim Caner. İşine yaradığına sevindim.

  4. ramazan 26 Şubat 2010 at 11:46 AM #

    saygılar…

  5. semih 17 Temmuz 2010 at 10:50 PM #

    Hocam, çok teşekkür ederim. Çok yararlı ve sade bir kod.
    Birşey sormak istiyorum. Bunun gibi onlarca label veya text varsa nasıl olacak her seferinde ayrı ayrı mı yazacağız

    • @bütün 18 Temmuz 2010 at 10:06 AM #

      Teşekürler,

      Birden fazla kontrol varsa, ben şöyle bir yöntemi tercih ediyorum..Yukarıdaki metota parametre olarak kontrolü de gönderiyorum 🙂

      delegate void updateLabelTextDelegate(string newText);

      private void updateLabelText(Control control, string newText)
      {
      if (control.InvokeRequired)
      {
      // worker thread
      updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
      control.Invoke(del, new object[] { newText });
      }
      else
      {
      // UI thread
      Label lab = (Label)control;
      lab.Text = newText;
      }
      }

      gibi…Umarım yardımı dokunur.

  6. semih 18 Temmuz 2010 at 2:09 PM #

    Aslında ben de böyle birşey denemiştim ama başaramamıştım (c#’da daha çok yeniyim). Sonra size yazdım.
    Kodu çalıştırmadım 🙁 🙁 Aşağıdaki kodu çalıştırınca
    “No overload for ‘updateLabelText’ matches delegate ‘RF_Remote_1.Form1.updateLabelTextDelegate'”
    hatasını alıyorum. 🙁

    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {

    mesaj = serialPort1.ReadLine();

    updateLabelText(label1, mesaj);
    }

    private void updateLabelText(Control control, string newText)
    {
    if (control.InvokeRequired)
    {
    // worker thread
    updateLabelTextDelegate del = new updateLabelTextDelegate(updateLabelText);
    control.Invoke(del, new object[] { newText });
    }
    else
    {
    // UI thread

    Label lab = (Label)control;
    lab.Text = newText;
    }
    }

    • @bütün 18 Temmuz 2010 at 9:05 PM #

      Hiçbirimiz anamızın karnında öğrenmedik bunları 🙂 merak etme yavaş yavaş tecrübe kazanırsın.

      Delegate tipini değitirmemiz lazım…Önceden updateLabelTextDelegate delegate’imiz yalnızca string tipinde bir parametre alıyordu ona şimdi bir de Control adlı yeni parametreyi aktarmamız lazım.

      Yani,

      delegate void updateLabelTextDelegate(string newText);

      tanımını

      delegate void updateLabelTextDelegate(Control control, string newText);

      şeklinde değiştirdikten sonra,

      control.Invoke(del, new object[] { newText });

      satırını da,

      control.Invoke(del, new object[] {control, newText });

      şeklinde değiştirirsen sanırım sorun çözülecektir.

      Yine de bir sorunla karşılaşırsan çekinme 🙂 Ben buralardayım…

  7. semih 19 Temmuz 2010 at 2:51 PM #

    Evet Ahmet hocam. Çok teşekkür ederim. İşimi çok kolaylaştıran ve programı ağırlaştırmayan bir kod oldu.
    İyi çalışmalar Diliyorum.

  8. Ahmet BÜTÜN 19 Temmuz 2010 at 6:51 PM #

    Rica ederim Semih…

    Yardımcı olabildiysem ne mutlu bana 🙂

  9. rasim 28 Haziran 2011 at 8:42 AM #

    çok teşekkür ederim.epey işime yaradı

  10. veli 22 Ağustos 2011 at 12:29 AM #

    yav kardeşim çok saolasın, harikasın valla 🙂 4 saattir bu hatayla uğraşıyodum en sonunda sayende hallettim.

Bir Cevap Yazın

Font Resize