Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从另一个c类更新gui#_C#_Multithreading_Class - Fatal编程技术网

C# 从另一个c类更新gui#

C# 从另一个c类更新gui#,c#,multithreading,class,C#,Multithreading,Class,嘿,我是新来的c#请帮忙。 我正在编写一个程序,对文件中的数据进行排序,这是一个耗时的过程,所以我认为应该在单独的线程中运行它,因为它有很多步骤,所以我为它创建了一个新类。问题是我想在主GUI中显示进度,我知道我必须使用Invoke函数,但问题是表单控制变量在这个类中无法访问。我该怎么办 示例代码: public class Sorter { private string _path; public Sorter(string path) { _path

嘿,我是新来的c#请帮忙。 我正在编写一个程序,对文件中的数据进行排序,这是一个耗时的过程,所以我认为应该在单独的线程中运行它,因为它有很多步骤,所以我为它创建了一个新类。问题是我想在主GUI中显示进度,我知道我必须使用Invoke函数,但问题是表单控制变量在这个类中无法访问。我该怎么办

示例代码:

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
    ,只要将引用传递给实例即可

使用另一个线程不会神奇地加快速度。不会,但会阻止他锁定UI。所有长时间运行的进程都应该在UI线程以外的线程上运行。您看过BackgroundWorker的使用吗?它不会使它更快,但GUI不会挂起,直到进程结束。@ShellShock:它不会使它更快,但会防止GUI在处理过程中锁定。事件将由调用线程调用,因此处理程序的执行仍不会在
窗体
线程的上下文中,除非以这种方式调用。在这种情况下,OP需要查看
ISynchronizeInvoke
。嗯,是的,您仍然需要在某个时候调用,因为事件将在工作线程上触发。嗯,好的。我已经删除了关于调用的注释,显然这仍然是需要的。但仍然使用事件是最优雅的解决方案。谢谢。工作完美无瑕。只是好奇,有没有办法从分类器类更新进度条???