2016-03-30 21 views
0

Sekme denetimi ve birkaç sekme içeren bir C# WinForms uygulamasına sahibim. Sekmelerden biri bir veri ızgarası kontrolü içerir - sadece yaklaşık 10 elemanı vardır, ancak veriler birden fazla sunucuyu sorgulayarak doldurulur ve bu nedenle yüklenmesi yavaştır.Bir datagrid denetimini doldururken iletiyi bekleyin

Uygulamamı çalıştırdığımda ve datagrid denetimi ile sekmeyi seçtiğimde, uygulama tüm sunucuları sorgulamaya ve ızgaraya nüfuz etmeye çalışırken uygulama askıda gibi görünüyor.

Asmak yerine uygulamanın yanıt vermesini istiyorum ve bunun için "lütfen bekle ..." mesajını görüntüleyelim, bu durum datagrid'in doldurulmasından sonra kaybolacaktır. Ben yapmaya çalıştım ne

gibi bir arka plan işçi yaratmaktır:

if (tabctrl.SelectedTab == tabctrl.TabPages["tabServices"]) 
{ 

    this.dgrdServices.RowPrePaint += new DataGridViewRowPrePaintEventHandler(dgrdServices_RowPrePaint); 
    this.dgrdServices.CellContentClick += new DataGridViewCellEventHandler(dgrdServices_CellClick); 

    BackgroundWorker bw = new BackgroundWorker(); 
    lblLoading.Visible = true; 
    bw.RunWorkerAsync(); 
    bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); 


} 

private void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 

    PopulateServicesDataGrid(); 
} 

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    lblLoading.Visible = false; 
} 

private void PopulateServicesDataGrid() 
{ 
    int x = 0; 

    foreach (Service Service in Globals.Services) 
    { 
     // Add a row to the datagrid for each service 
     this.dgrdServices.Rows.Add(); 

     // Update the current service status 
     Service.Status = Service.Query(Service.Server, Service.Name); 
     if (Service.Status == "running") 
     { 
      this.dgrdServices.Rows[x].Cells[0].Value = Properties.Resources.green_dot; 
      this.dgrdServices.Rows[x].Cells[4].Value = Properties.Resources.stop_enabled; 
     } 
     else 
     { 
      this.dgrdServices.Rows[x].Cells[0].Value = Properties.Resources.grey_dot; 
      this.dgrdServices.Rows[x].Cells[4].Value = Properties.Resources.start_enabled; 
     } 

     this.dgrdServices.Rows[x].Cells[1].Value = Service.Server.ToUpper(); 
     this.dgrdServices.Rows[x].Cells[2].Value = Service.FreindlyName; 
     this.dgrdServices.Rows[x].Cells[3].Value = Service.Status; 
     this.dgrdServices.Rows[x].Cells[5].Value = "Uninstall"; 
     this.dgrdServices.Rows[x].Cells[6].Value = Service.Name; 
     x++; 
    } 
} 

PopulateServicesDataGrid() kodunu içeren servis durumu için bazı nesneler ve sorguları birkaç farklı sunucular arasında dolaşır.

Yukarıdakileri denediğimde ve çalıştırdığımda, ızgara dolu değil. Bir arka plan çalışanı kullanmıyor ve sadece PopulateServicesDataGrid'i doğrudan çağırıyorsam (her ne kadar uygulama kilitleniyorsa) çalışır.

Arka plan worker/datagrid neden çalışmıyor?

+1

E parametresindeki RunWorkerCompleted olayındaki hataları kontrol etmeniz gerekir. Olayları kancalamadan önce RunWorkerAsync() koşmak sadece garip görünüyor. PopulateServicesDataGrid öğenizi yayınlamamak size yardımcı olmamıza yardımcı oluyor. – LarsTech

+0

Arka plan çalışan ayrı bir işlemdir ve ızgarada görüntülenmez. Sunucunun sorguları, backgroundworker'ın bir DataTable döndürdüğü arka plan çalışanında olmalıdır. Ardından DataGrid'i döndürülen DataTable'ı kullanarak doldurun. – jdweng

+0

PopulateServiceDataGrid yayınlandı. – Brad

cevap

1

PopulateServicesDataGrid'inizde, UI denetimiyle etkileşim kurduğunuzu hayal ediyorum; bu, arka plan işçisinin UI içeriğinizden farklı bir iş parçacığı üzerinde çalıştığı için çalışmaz. İşi, kılavuza yerleştirmek istediğiniz bilgileri döndüren ve daha sonra kullanıcı arabirim içeriğinize (RunWorkerCompleted) geri döndürecek bir şekilde çalışması için bir mekanizma çalışması yapmanız gerekir. İşi yapmak.

Herhangi bir arka plan çalışanı kullanmanız gerektiğinde, UI denetimleriyle etkileşimlerinizi bölmeniz ve arka plan çalışmasının UI'nizle yeniden etkileşim etkileşimini tamamlaması gerekir.

Ayrıca, RunWorkerAsync'i çağırarak olayları karıştırıyorsunuz, ilk olarak olaylarınızı bağlayın ve sonra RunWorkerAsync'i arayın. Eğer gördüğüm koduna göre, bu yapabileceğini nasıl

Kaba bir örnek:

Düzenleme bir örnekle yorumunu yansıtacak.

private void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    QueryServices() 
} 

private void QueryServices() 
{ 
    foreach (Service Service in Globals.Services) 
    { 
     Service.Status = Service.Query(Service.Server, Service.Name); 
    } 
} 

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     PopulateServicesDataGrid(); 
     lblLoading.Visible = false; 
    } 

    private void PopulateServicesDataGrid() 
    { 
     //Do everything else you are doing originally in this method minus the Service.Query calls. 
    } 
+0

Taşınmış RunWorkerAsync sonuna - teşekkürler! Bilgileri tekrar şebekeye nasıl döndüreceğinize dair herhangi bir öneriniz var mı? – Brad

+0

@Brad'den önce çok işlem görmedim Daha önce Globals.Services'te bir koleksiyonunuz var gibi görünüyor, bunun için çok tuhaf bir yol var ama bununla birlikte çalışmak zorundasınız. Foreach'ınıza devam edebilir ve her birinde sorgulama araması yapabilirsiniz. Tamamlanan olayda, bunları geri alın ve yöntemde zaten var olan UI tabanlı mantığı gerçekleştirin. Bu, çalışanın tamamlanmasından sonra Service.Status'un durumunu koruyacağı varsayılmaktadır, ki bu şu anda gösterilen kodun% 100'ünü kullanmıyorum. – davidallyoung

+0

Üzgünüz, bir düzine kez yanıtınızı okudum. Önerdiğin şeyi takip ettiğimden emin değilim. Detaylandırır mısınız, açıklığa kavuşturur musunuz? Belki bir örnekle? Afedersiniz! – Brad

1

Yöntem bw_Do ThreadPool'dan başka bir iş parçacığında çalışıyor. Diğer iş parçacıklarından WinForms nesnesine erişme, senkronizasyon gerektirir. Bunu yapmanın en iyi yolu - AsyncOperationManager'ı kullanın. GUI iş parçacığında AsyncOperation oluşturmalı ve sonuçları göndermek veya göndermek için PopulateServicesDataGrid içinde kullanmalısınız. Başka bir yol - Datawrid'i bw_RunWorkerComplete içinde hazırlanmış verilerle güncelleyin - daha önceden BackgroundWorker bileşeni tarafından senkronize edilmiştir.

Aynı şeyi yapmanın daha modern bir yolu - uyumsuz görevleri kullanır, ancak temel düzeyde TPL bilgisi gerektirir.