我有一个显示树视图的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);
}
}
答案 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();
}
}
}