使用c#代码逐一更新Label控件
本文关键字:更新 Label 控件 代码 使用 | 更新日期: 2023-09-27 17:52:41
我有一个windows窗体的标签控件,我有一个代码如下所示:-
我在代码中添加了一些额外的行,我做了进一步的工作。但是,Label控件仍然没有一个一个地更新。
void function1()
{
FOLDER1 = DRIVE + @":'Foldername1";
LOGFILE1 = FOLDER1 + @"'Foldername2";
Process msbuild;
msbuild = new Process();
DEVENV = Environment.GetEnvironmentVariable("VS100COMNTOOLS") + @"..'IDE'devenv.exe";
var list = System.IO.Directory.GetFiles(LOGFILE1);
foreach (var item in list)
{
System.IO.File.Delete(item);
}
// Creation of array of string to Build Projects before Building Up.
array[0] = @"'make'versionupdate'versionupdate_vs2010.sln /build Release";
for (int k = 0; k < array.Length; k++)
{
msbuild.StartInfo.UseShellExecute = false;
msbuild.StartInfo.CreateNoWindow = true;
msbuild.StartInfo.Arguments = FOLDER1 + array[k] + @" /out " + LOGFILE1;
msbuild.StartInfo.FileName = DEVENV;
msbuild.Start();
msbuild.WaitForExit();
UpdateProgress();
}
}
void UpdateProgress()
{
if (InvokeRequired)
{
MethodInvoker method = new MethodInvoker(UpdateProgress);
Invoke(method);
return;
}
if(checkbox1.Checked)
{
for (int k = 0; k < array.Length; k++)
{
this.lbl_CurrentProject.Text = "Current Project: " + @" " + array[k];
progressBar1.Value = int.Parse(((k * 100) / array.Length).ToString());
progressBar1.CreateGraphics().DrawString(((k * 100) / array.Length).ToString() + "%", new Font("Arial", (float)10.25, FontStyle.Bold), Brushes.Black, new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7));
System.Threading.Thread.Sleep(100);
progressBar1.PerformStep();
progressBar1.Refresh();
}
}
}
private void bn_Start_Click(object sender, EventArgs e)
{
if (checkbox1.Checked)
{
if (string.IsNullOrEmpty(cmb_drive.Text))
{
DRIVE = "-";
}
else
{
DRIVE = cmb_drive.GetItemText(cmb_drive.SelectedItem);
}
if (thread1 != null)
{
thread1.Abort();
}
thread1 = new Thread(function1);
thread1.Start();
}
}
这里发生的事情是标签控件没有一个一个地更新。当项目在字符串数组中构建时,我想更新标签控件,而不是一次全部更新。
请帮我处理一下上面的代码。谢谢。
你需要使用BackgroundWorker
,因为你不能从另一个线程更新控件。
正确的方法-是使用BackgroundWorker为您的目的。另一种方法(几乎正确的方法)-使用Control.Invoke
方法。还有另一种几乎正确的方法——使用SynchronizationContext。
E。委托更新进度条根据你最后的评论,你可以使用下面的delegatemmethod
void UpdateProgress()
{
if (InvokeRequired)
{
MethodInvoker method = new MethodInvoker(UpdateProgress);
Invoke(method);
return;
}
if(checkbox1.Checked)
{
for (int k = 0; k < array.Length; k++)
{
this.Invoke((MethodInvoker)delegate {
this.lbl_CurrentProject.Text = "Current Project: " + @" " + array[k];
progressBar1.Value = int.Parse(((k * 100) / array.Length).ToString());
progressBar1.CreateGraphics().DrawString(((k * 100) / array.Length).ToString() + "%", new Font("Arial", (float)10.25, FontStyle.Bold), Brushes.Black, new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7));
System.Threading.Thread.Sleep(100);
progressBar1.PerformStep();
progressBar1.Refresh();
});
}
}
像往常一样(其他人已经提到过),您不能在gui线程中执行任何长时间运行的工作,否则它将冻结并且用户无法再交互。BackgroundWorker
的存在就是为了这个目的。它在另一个线程中运行负载,并且允许在gui线程运行时(通过ReportProgress()
)或完成时(通过RunWorkerCompleted
回调)轻松返回到gui线程以更新gui。
我刚刚写了一个简单的例子,它展示了使用后台工作器的概念(可能还有一种或其他技术来改进你的代码):
public Form1()
{
InitializeComponent();
// ToDo: Refactor this into a method that will be called
// on some kind of event (eg. button click).
var rootFolder = @"D:'Root";
var outputFolder = Path.Combine(rootFolder, @"'Bin'Release");
var solutions = GetAvailableSolutions(rootFolder);
var arguments = solutions.Select(solution => String.Join(" ", solution, "/build Release", "/out " + outputFolder));
var processes = arguments.Select(CreateMsBuildProcess);
var worker = new BackgroundWorker();
worker.DoWork += OnWorkerDoWork;
worker.ProgressChanged += OnWorkerProgressChanged;
worker.RunWorkerCompleted += OnWorkerRunWorkerCompleted;
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
// ToDo: Disable start button
ClearFolder(outputFolder);
worker.RunWorkerAsync(processes);
}
private IEnumerable<String> GetAvailableSolutions(String rootFolder)
{
// ToDo: Change retrieving of .sln files to any logic you alike.
return Directory.EnumerateFiles(rootFolder, "*.sln", SearchOption.AllDirectories);
}
private void OnWorkerDoWork(object sender, DoWorkEventArgs e)
{
var index = 0;
var worker = (BackgroundWorker)sender;
// ToDo: Give in a self created class instead of process to easier
// access the needed text for ReportProgress().
var processes = (IEnumerable<Process>)e.Argument;
foreach (var process in processes)
{
if (worker.CancellationPending)
break;
worker.ReportProgress(index, process.StartInfo.Arguments);
process.Start();
process.WaitForExit();
}
}
private void OnWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
var text = (String)e.UserState;
// ToDo: Update label and progress bar.
// Eg. label.Text = text; progressBar.PerformStep(); or progressBar.Value = e.ProgressPercentage;
}
private void OnWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// ToDo: Enable Start button.
// Eg. buttonStart.Enabled = true;
}
private static void ClearFolder(String folder)
{
if (Directory.Exists(folder))
Directory.Delete(folder, true);
Directory.CreateDirectory(folder);
}
private static Process CreateMsBuildProcess(String arguments)
{
var devEnvPath = Path.Combine(Environment.GetEnvironmentVariable("VS100COMNTOOLS"), @"..'IDE'devenv.exe");
var startInfo = new ProcessStartInfo
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = arguments,
FileName = devEnvPath
};
var process = new Process { StartInfo = startInfo };
return process;
}
由于评论而更新:我做错了什么?
差不多什么都有。似乎您没有花任何时间使用我提供的代码示例,因为我展示了如何使用BackgroundWorker
,而您使用了Thread
(错误的方式)。看来你很幸运地挑了我的好日子。我将给出表单(或控件)构造函数中需要提供的代码以及在按钮click事件中需要调用的代码:
private BackgroundWorker _Worker;
public Form1()
{
InitializeComponent();
// Maybe other stuff you initialize within the ctor...
_Worker = new BackgroundWorker();
_Worker.DoWork += OnWorkerDoWork;
_Worker.ProgressChanged += OnWorkerProgressChanged;
_Worker.RunWorkerCompleted += OnWorkerRunWorkerCompleted;
_Worker.WorkerSupportsCancellation = true;
_Worker.WorkerReportsProgress = true;
}
private void bn_Start_Click(object sender, EventArgs e)
{
string drive;
if (checkbox1.Checked)
{
if (string.IsNullOrEmpty(cmb_drive.Text))
{
drive = "-";
return;
}
else
{
drive = cmb_drive.GetItemText(cmb_drive.SelectedItem);
}
if (_Worker.IsBusy)
{
_Worker.CancelAsync();
// ToDo: Update gui by disable buttons, etc and show that cancelation is pending.
// The enabling of the buttons, etc should happen in OnWorkerRunWorkerCompleted()
return;
}
var rootFolder = Path.Combine(drive + ":", "Foldername1");
var outputFolder = Path.Combine(rootFolder, @"Foldername2");
var solutions = GetAvailableSolutions(rootFolder);
var arguments = solutions.Select(solution => String.Join(" ", solution, "/build Release", "/out " + outputFolder));
var processes = arguments.Select(CreateMsBuildProcess);
// ToDo: Disable start button and update gui that processing has started.
// btn_Start.Enabled = false;
ClearFolder(outputFolder);
_Worker.RunWorkerAsync(processes);
}
}