2016-04-25 2 views
0

私はツリービューを表示するguiフォームを持っています。背景作業者がツリービューを構築している間、マーキーの進捗バーを使用するアラートフォームを表示します。私が持っている問題は、マーキーが表示されず、doworkが実行されている間ではなく、GUIに制御が戻るまで、progresschangedルーチンが起動しないということです。Backgroundworker_progresschangedは、コントロールがGUIに戻るときにのみ呼び出されます

誰も私が間違ってこれをコード化しているか、それがどのように動作するかを誤解しているか否かの判断が支援していただけますか?ありがとう。

セットアップ:

  alert = new AlertForm(); 
      alert.Message = string.Format("Building folder tree ({0}), please wait.", Global.RootDir); 
      // event handler for the Cancel button in AlertForm 
      alert.Cancelled += new EventHandler<EventArgs>(btnExit_Click); 
      alert.Show(); 
      backgroundWorker1.WorkerReportsProgress = true; 
      backgroundWorker1.WorkerSupportsCancellation = true; 

      backgroundWorker1.DoWork += backgroundWorker1_DoWork; 
      backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted; 
      backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged; 

      backgroundWorker1.RunWorkerAsync(); 

バックグラウンドワーカーコード(.ReportProgressの上にではなくbackgroundWorker1_ProgressChangedにデバッグ段階):

worker running - no marquee in gui

worker complete - marquee displays in gui:表示されているもの

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     backgroundWorker1.ReportProgress(1); 
     Invoke(new MethodInvoker(() => CreateTreeView(treeView1))); 
    } 

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     alert.Refresh(); 
    } 

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     alert.Close(); 
     if (treeView1.Nodes.Count > 0) 
     { 
      treeView1.ExpandAll(); 
      treeView1.TopNode = treeView1.Nodes[0]; 
     } 
    } 

==============================================私は、新しいツリービューオブジェクトを作成するにそののクローニングになってしまっている下のコメントに基づいて==========================

GUIオブジェクト。

 TreeView treeView = new TreeView(); 
     CreateTreeView(treeView); 


     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Cancelled) 
     { 
      if (Global.Error) 
      { 
       _alert.Close(); 
       string errorMessage = Global.ErrorMessage; 
       MessageBox.Show(errorMessage, @"Error occurred", MessageBoxButtons.OK); 
       Global.Error = false; 
      } 
     } 
     else 
     { 
      TreeView treeView = (TreeView)e.Result; 
      CopyTreeNodes(treeView, treeView1); 
      if (treeView1.Nodes.Count > 0) 
      { 
       treeView1.ExpandAll(); 
       treeView1.TopNode = treeView1.Nodes[0]; 
      } 
      _alert.Close(); 
      treeView = null; 
     } 

    } 

    public void CopyTreeNodes(TreeView treeViewSource, TreeView treeViewTarget) 
    { 
     foreach (TreeNode node in treeViewSource.Nodes) 
     { 
      TreeNode treeNode = new TreeNode(node.Text, node.ImageIndex, node.SelectedImageIndex); 
      CopyNodeChildren(treeNode, node); 
      treeViewTarget.Nodes.Add((TreeNode)node.Clone()); 
     } 
    } 

    public void CopyNodeChildren(TreeNode parent, TreeNode original) 
    { 
     foreach (TreeNode tn in original.Nodes) 
     { 
      TreeNode treeNode = new TreeNode(tn.Text, tn.ImageIndex, tn.SelectedImageIndex); 
      parent.Nodes.Add((TreeNode)tn.Clone()); 
      CopyNodeChildren(treeNode, tn); 
     } 
    } 
+0

なし*実際に*ワーカースレッド上で実行されません。 Invoke()をすぐに呼び出してUIスレッド上で実行します。もちろん、コードが完了するまで何かが再描画されないようにします。このコードがワーカースレッド上で実行できることはほとんどありません。また、ワーカースレッドを使用しても多くの助けを借りることはありませんが、ユーザーはまだ仕事が完了するのを待っています。非常に大きなTreeViewの標準的な手法は、ユーザが展開するまで、実際のノードに置き換えられないダミーノードを追加することです。 –

答えて

0

私はあなたが使用しているのC#のバージョンに関する仮定を行うことができますが、4.5以降を使用している場合は、非同期に動作することができますならば、あなたはBackgroundWorkerを必要としない/あなたのコードの中にパターンを待っています。います欠点は、既存のコードベースで動作するasync/awaitが時には困難になることです。

Form1はアラートフォームを表示して動作を開始します。警告フォームには、操作をキャンセルするために使用できるCancellationTokenSourceがあります。 CallTreeViewは非同期に実行されます。キャンセルボタンをクリックすると中止されます。プログレスバーは単純にマーキースタイルに設定されています。インクリメントする必要はありません。また、何かを行う必要はありません。アラートフォームが開いている時間全体をパルスします。

をForm1:

using System; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private async void button1_Click(object sender, EventArgs e) 
     { 
      AlertForm af = new AlertForm(); 
      af.Show(); 

      //I assume CallTreeView is not implemented in your form's code behind, 
      //if it is you do not need to pass it as a parameter 
      await Task.Run(async() => await CallTreeView(treeView1, af.Cts.Token)); 

      af.Close(); 
     } 

     private async Task CallTreeView(TreeView tv, CancellationToken token) 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       if (token.IsCancellationRequested) 
       { 
        //clean up whatever you need to 
        return; 
       } 
       else 
       { 
        await Task.Delay(500); //just simulate doing something 
        //add nodes... 
       } 
      } 
     } 
    } 
} 

アラートフォーム:あなたのコードの

using System; 
using System.Threading; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class AlertForm : Form 
    { 
     public CancellationTokenSource Cts { get; set; } 

     public AlertForm() 
     { 
      InitializeComponent(); 
      Cts = new CancellationTokenSource();    
     } 

     private void Cancel_Click(object sender, EventArgs e) 
     { 
      Cts.Cancel(); 
     } 
    } 
} 
+0

ご協力いただきありがとうございます。私はCrowcodersのアプローチを試みたが、マーキーはまだ空白のままだった。 Hansのコメントに基づいて私はInvokeの代わりにCreateTreeViewの代理人を使用するように切り替えましたが、マーキーが実行され、TreeViewがCreateTreeViewの下に作成されてクロススレッドエラーが発生していました。 –

+0

私が今働いている解決策は、新しいツリービューオブジェクトを構築し、それを.workercompletedのGUIツリービューに複製することです。 –

関連する問題