【问题标题】:c# How to change/access WinForms controls from a different classc# 如何从不同的类更改/访问 WinForms 控件
【发布时间】:2015-09-17 18:13:26
【问题描述】:

所以我试图从一个 WinForms 项目中更改文本,从另一个类而不是 Form 类。 它应该像这样工作:

但它会这样做:

我过去的做法是将对象作为参数传递给我的其他类,然后我可以从其他类更改文本。我对进度条做同样的事情,它确实在那里工作,所以它与进度条一起工作而不是标签很奇怪。

我用这个方法来改变进度条:

public void IncreaseProgress(int progBarStepSize, String statusMsg, int currentProject=-1) {
   if (currentProject != -1) {
      lblStatus.Text = String.Format("Status: {0} | project {1} of {2}",statusMsg,currentProject,ProjectCount);
   }
   else {
      lblStatus.Text = String.Format("Status: {0}",statusMsg);
   }

   pb.Increment(progBarStepSize);
}

这里是我使用该方法的地方:

public void InitialiseFile(List<string> filePaths, int eurojobType)
{
    foreach (string sheet in outputSheets) {
        switch (sheet) {
            case "Summary":
                for (int i = 0; i < filePaths.Count; i++) {
                            var filePath = filePaths[i];
                    IncreaseProgress(1, "Reading Summary", i);
                    worksheetIn = excelReader.ReadExcelSummary(filePath);

                    IncreaseProgress(1, "Writing Summary", i);
                    excelWriter.WriteExcelSummary(worksheetIn);
                }
                break;
            case "Monthly_Cat1":
                for (int i = 0; i < filePaths.Count; i++) {
                    var filePath = filePaths[i];
                    IncreaseProgress(1, "Reading Monthly", i);
                    worksheetIn = excelReader.ReadExcelMonthly(filePath);

                    IncreaseProgress(1, "Writing Monthly", i);
                    excelWriter.WriteExcelMonthly(worksheetIn);
                }
                break;
        }
    }
    IncreaseProgress(1, "Completed!");
}

现在我知道此代码有效,因为进度条会增加。它应该跳入第一个 if 循环,因为 i 被作为参数传递,而不是 -1

//manager class
private Label lblStatus;
private ProgressBar pb;

public Manager(ProgressBar pb, Label lbl){
    this.pb = pb;
    lblStatus = lbl;
}

//Form class
Manager mgr = new Manager(progressBar1, lblStatus, projectFilePaths.Count, outputSheets.ToArray(), exportPath);
mgr.InitialiseFile(projectFilePaths, eurjobType);

【问题讨论】:

  • 不要在 UI 线程上做阻塞工作。
  • Edward,花点时间回顾一下Tasks 和异步模式;以及IProgress&lt;T&gt; 接口
  • @SLaks,你到底是什么意思?整个 mgr.InitialiseFile() 方法应该在一个后台工作者中,这样 UI 就不需要等待方法完成了吗?
  • 是的;或者,更好的是,使用await Task.Run()
  • 添加了一个 Task.Run 示例。

标签: c# winforms label progress-bar


【解决方案1】:

您可以在设置Text 后调用lblStatus.Refresh(); 来强制重绘控件。 但是考虑一下 Slaks 的评论:

不要在 UI 线程上做阻塞工作

您可以考虑改用 BackgroundWorker 或 Task.Run 或 async/await 模式。

举个例子:

private async void button1_Click(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        for (int i = 0; i < 10000; i++)
        {
            this.Invoke(new Action(() =>
            {
                label1.Text = i.ToString();
                label1.Refresh();
            }));
        }
    });
}

这样数字会增加,标签会刷新并显示新值,同时 UI 是响应式的,例如您可以移动表单或单击其他按钮。

您应该将您的 UI 相关代码放在由Invoke 触发的操作中,以防止收到跨线程操作异常。

【讨论】:

  • 我会接受这个作为回答,因为lblStatus.Refresh(); 确实有效。但我确实看到了使用后台工作人员的担忧,因为正如 SLaks 所说,表单会冻结在执行多个文件时。
  • @Edward 所以使用测试表单中的示例代码并查看结果。您可以移动表单、最小化、最大化、单击其他按钮等,而不会冻结表单。事实上,Task.Run 中的代码运行在 UI 线程之外的另一个线程上。
  • @Edward 你也可以看到这个answer
猜你喜欢
  • 1970-01-01
  • 2011-02-10
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多