c# 如何 change/access 来自不同 class 的 WinForms 控件

c# How to change/access WinForms controls from a different class

因此,我正在尝试从另一个 class 而非表单 class 更改 WinForms 项目中的文本。 它应该像这样工作:

但它是这样做的:

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

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

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);

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

Don't do blocking work on the UI thread

您可以考虑改用 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 触发的操作中,以防止收到跨线程操作异常。