通过另一个 class 更新标签

Update label through another class

我正在尝试调用 script1 中的方法 Run。然后从 script1 调用方法 alertwait 并尝试更新 Form1 中的 statusLabel。但是这段代码有错误。

static Label status = this.Controls.Find("statusLabel", true).FirstOrDefault() as Label;

此代码仅适用于 Form1。因为this return 错误在另一个类。也许它不正确,您知道更好的解决方案。

P.S。我知道如何解决这个问题(见下文 "Not the best solution"),但代码将是 ~ 10-30 行。

项目

Form1.cs

public partial class Form1 : Form
{
    private void statusLabel_Click(object sender, EventArgs e)
    {
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        script1.Run();
        ...
        script30.Run();
    }
}

function.cs(常用函数)

public class function
{
    static Label statusLabel = this.Controls.Find("statusLabel", true).FirstOrDefault() as Label;

    static public void alert(string str)
    {
        statusLabel.Text = str;
    }

    static public void wait(int sec)
    {
        int i = 0;
        while (i++ < sec)
        {
            statusLabel.Text = "Wait: " + (sec+1-i).ToString();
            Thread.Sleep(1000);
        }
    }
}

script1.cs (script1,script2 ...大概是30个小程序)

public class script1
{
    static public void Run()
    {
        function.alert("Script1 is running");
        function.wait(5);
        function.alert("Script1 is done");
    }
}

不是最佳解决方案

在 function.cs

中删除
static Label status = this.Controls.Find("statusLabel", true).FirstOrDefault() as Label;

Form1.cs

public partial class Form1 : Form
{
    private void Form1_Load(object sender, EventArgs e)
    {
        script1.Run(this.statusLabel);
    }
}

function.cs

public class function
{
    private Label _statusLabel;

    public scriptClass(Label statusLabel)
    {
        _statusLabel = statusLabel;
    }
}

script1.cs (script1,script2 ...大概是30个小程序)

public class script1
{

    static public void Run(Label statusLabel)
    {
        function _function = new function(statusLabel);
    }
}

statusLabel 对象由 Form1 class 拥有,应该被封装和隐藏。为确保 classes 的良好解耦以及适当的数据隐藏,只有 Form1 class 应该直接访问它。它应该(默认情况下)能够通过名为 statusLabel 的字段访问它(即不需要调用 this.Controls.Find() (甚至不应该从 function class ,因为 class 也不是对象的所有者,也不是 Controls 属性).

正确的做法是 script1 class 公开一个 StatusText 属性,以及 属性 时引发的事件] 值变化。有两种规范的方式来实现事件:

  1. 实施名为 StatusTextChanged
  2. 的事件
  3. 实现INotifyPropertyChanged接口

请注意,在您的示例中,#2 不是一个选项,因为您正在使用静态 classes 来实现您的脚本。恕我直言,由于各种原因,这是不可取的,但由于 #1 是一个非常好的解决方案,我不会在这一点上重复。 :)

第一个看起来像这样:

class script1
{
    public static string StatusText { get; private set; }
    public static event EventHandler StatusTextChanged;

    static public void Run()
    {
        ChangeStatusText("Script1 is running");
        function.wait(5);
        ChangeStatusText("Script1 is done");
    }

    static void ChangeStatusText(string text)
    {
        StatusText = text;

        EventHandler handler = StatusTextChanged;

        if (handler != null)
        {
            handler(null, EventArgs.Empty);
        }
    }
}

然后在 Form1:

public partial class Form1
{
    private void Form1_Load(object sender, EventArgs e)
    {
        script1.StatusTextChanged += (sender1, e1) => statusLabel.Text = script1.Text;
        script1.Run();
        ...
        script30.StatusTextChanged += (sender1, e1) => statusLabel.Text = script30.Text;
        script30.Run();
    }
}

注意在上面,每个scriptX class 都必须重新实现事件。您可以创建一个基础 class,每个 scriptX classes 都继承该基础,并且其中包含相关事件。那么Form1class只需要订阅一个baseclass事件即可。它还将解决或至少减少让事件处理程序订阅 30 个不同事件的问题。

当然,在这种情况下 Form1 class 将不知道哪个脚本正在更新文本,但在您的情况下这可能无关紧要。

另请注意,如果您 确实 使 scriptX class 非静态,您可能会再次 运行 进入问题必须多次订阅。但这更容易处理,因为在那种情况下您似乎肯定会使用基 class,因此很容易将 "subscribe, run script, unsubscribe" 逻辑概括为辅助方法。