C# 从另一个c类更新gui#
嘿,我是新来的c#请帮忙。 我正在编写一个程序,对文件中的数据进行排序,这是一个耗时的过程,所以我认为应该在单独的线程中运行它,因为它有很多步骤,所以我为它创建了一个新类。问题是我想在主GUI中显示进度,我知道我必须使用Invoke函数,但问题是表单控制变量在这个类中无法访问。我该怎么办 示例代码:C# 从另一个c类更新gui#,c#,multithreading,class,C#,Multithreading,Class,嘿,我是新来的c#请帮忙。 我正在编写一个程序,对文件中的数据进行排序,这是一个耗时的过程,所以我认为应该在单独的线程中运行它,因为它有很多步骤,所以我为它创建了一个新类。问题是我想在主GUI中显示进度,我知道我必须使用Invoke函数,但问题是表单控制变量在这个类中无法访问。我该怎么办 示例代码: public class Sorter { private string _path; public Sorter(string path) { _path
public class Sorter
{
private string _path;
public Sorter(string path)
{
_path = path;
}
public void StartSort()
{
try
{
processFiles(_path, "h4x0r"); // Just kidding
}
catch (Exception e)
{
MessageBox.Show("Error: " + e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void processFiles(string Dir, string[] key)
{
/* sorting program */
}
它被用作
public partial class Form1 : Form
{
Sorter sort;
public Form1()
{
InitializeComponent();
}
private void browseBtn_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
textBox1.Text = folderBrowserDialog1.SelectedPath;
}
private void startBtn_Click(object sender, EventArgs e)
{
if (startBtn.Text == "Start Sorting")
{
Thread worker = new Thread(new ThreadStart(delegate() {
sort = new Sorter(textBox1.Text);
sort.StartSort(); }));
worker.start();
}
else
MessageBox.Show("Cancel");//TODO: add cancelling code here
}
}
plz help..向正在执行多线程工作的类添加一个事件,该事件在进度更改时触发。让您的表单订阅此事件并更新进度栏 注意ProgressEventArgs是一个继承EventArgs的小类,它有一个用于进度的整数
// delegate to update progress
public delegate void ProgressChangedEventHandler(Object sender, ProgressEventArgs e);
// Event added to your worker class.
public event ProgressChangedEventHandler ProgressUpdateEvent
// Method to raise the event
public void UpdateProgress(object sender, ProgressEventArgs e)
{
ProgressChangedEventHandler handler;
lock (progressUpdateEventLock)
{
handler = progressUpdateEvent;
}
if (handler != null)
handler(sender, e);
}
我建议你仔细阅读这门课。它正是为了解决您试图解决的问题,并且使事情比自己手动线程化容易得多 简例
public Form1()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
}
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void btnStart_Click(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i < 101; ++i)
{
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
//Sort Logic is in here.
Thread.Sleep(250);
backgroundWorker.ReportProgress(i);
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy && backgroundWorker.WorkerSupportsCancellation)
backgroundWorker.CancelAsync();
}
public Form1()
{
初始化组件();
backgroundWorker.WorkerReportsProgress=true;
backgroundWorker.WorkerSupportsScanCellation=true;
backgroundWorker.ProgressChanged+=新的ProgressChangedEventHandler(backgroundWorker\u ProgressChanged);
}
void backgroundWorker\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
progressBar1.值=e.ProgressPercentage;
}
私有void btnStart_单击(对象发送方,事件参数e)
{
如果(!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
私有void backgroundWorker_DoWork(对象发送方,DoWorkEventArgs e)
{
对于(int i=1;i<101;++i)
{
if(backgroundWorker.CancellationPending)
{
e、 取消=真;
打破
}
其他的
{
//排序逻辑在这里。
睡眠(250);
后台工作人员报告进度(一);
}
}
}
私有void btnCancel\u单击(对象发送者,事件参数e)
{
if(backgroundWorker.IsBusy&&backgroundWorker.worker支持扫描单元)
backgroundWorker.CancelAsync();
}
您可以这样做:
public delegate void StatusReporter(double progressPercentage);
public class MainClass
{
public void MainMethod()
{
Worker worker = new Worker(ReportProgress);
ThreadStart start = worker.DoWork;
Thread workThread = new Thread(start);
workThread.Start();
}
private void ReportProgress(double progressPercentage)
{
//Report here!!!
}
}
public class Worker
{
private readonly StatusReporter _reportProgress;
public Worker(StatusReporter reportProgress)
{
_reportProgress = reportProgress;
}
public void DoWork()
{
for (int i = 0; i < 100; i++ )
{
// WORK, WORK, WORK
_reportProgress(i);
}
}
}
public delegate void StatusReporter(双倍百分比);
公共类主类
{
公共方法()
{
工人=新工人(报告进度);
ThreadStart=worker.DoWork;
线程工作线程=新线程(开始);
workThread.Start();
}
私有void报告进度(双倍进度百分比)
{
//在这里报道!!!
}
}
公社工人
{
私有只读StatusReporter\u reportProgress;
公共工作人员(进度报告员)
{
_reportProgress=reportProgress;
}
公共工作
{
对于(int i=0;i<100;i++)
{
//工作,工作,工作
_报告进展情况(一);
}
}
}
有几个选项可以解决这类问题。在任何情况下,您都必须修改Invoke
,以更新UI
你可以
- …添加一个在新类上激发的事件,您的UI可以侦听该事件,并在适用时调用该事件-您仍然需要将数据传递给工作类(通过构造函数、属性、方法调用等)
- …将该方法作为方法保留在窗体上,并保留从中启动新线程的方法(毕竟,新线程不必在其他类中启动)
- …将控件上的访问修饰符更改为(例如)
,以便同一程序集中的任何类都可以internal
调用对控件的更改,或从中读取
- …使您的worker类成为它需要访问的窗体的子级-然后,它可以查看其父级的
,只要将引用传递给实例即可private
窗体
线程的上下文中,除非以这种方式调用。在这种情况下,OP需要查看ISynchronizeInvoke
。嗯,是的,您仍然需要在某个时候调用,因为事件将在工作线程上触发。嗯,好的。我已经删除了关于调用的注释,显然这仍然是需要的。但仍然使用事件是最优雅的解决方案。谢谢。工作完美无瑕。只是好奇,有没有办法从分类器类更新进度条???