Backgroundworker_progresschanged仅在控制返回gui

时间:2016-04-25 11:38:27

标签: c# treeview backgroundworker

我有一个显示树视图的gui表单。我显示一个使用选取框进度条的警报表单,而后台工作程序构建树视图。我遇到的问题是,如果控件返回到gui,而不是在dowork运行时,则不显示选取框并且progresschanged例程不会触发。

任何人都可以协助我是否错误地编码或误解了它应该如何工作?谢谢。

设置:

            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):

    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];
        }
    }

显示的内容:

worker running - no marquee in gui

worker complete - marquee displays in gui

=============================================== =========================

根据下面的评论,我最终创建了一个新的treeview对象,然后将其克隆到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);
        }
    }

1 个答案:

答案 0 :(得分:0)

我正在假设您正在使用的c#版本,但如果您使用的是4.5或更高版本,那么如果您可以在代码中使用async / await模式,则不需要BackgroundWorker。缺点是异步/等待现有代码库有时会遇到挑战。

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();
        }
    }
}