通过另一个 class 更新标签
Update label through another class
我正在尝试调用 script1
中的方法 Run
。然后从 script1
调用方法 alert
或 wait
并尝试更新 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
属性,以及 属性 时引发的事件] 值变化。有两种规范的方式来实现事件:
- 实施名为
StatusTextChanged
的事件
- 实现
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 都继承该基础,并且其中包含相关事件。那么Form1
class只需要订阅一个baseclass事件即可。它还将解决或至少减少让事件处理程序订阅 30 个不同事件的问题。
当然,在这种情况下 Form1
class 将不知道哪个脚本正在更新文本,但在您的情况下这可能无关紧要。
另请注意,如果您 确实 使 scriptX
class 非静态,您可能会再次 运行 进入问题必须多次订阅。但这更容易处理,因为在那种情况下您似乎肯定会使用基 class,因此很容易将 "subscribe, run script, unsubscribe" 逻辑概括为辅助方法。
我正在尝试调用 script1
中的方法 Run
。然后从 script1
调用方法 alert
或 wait
并尝试更新 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
属性,以及 属性 时引发的事件] 值变化。有两种规范的方式来实现事件:
- 实施名为
StatusTextChanged
的事件
- 实现
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 都继承该基础,并且其中包含相关事件。那么Form1
class只需要订阅一个baseclass事件即可。它还将解决或至少减少让事件处理程序订阅 30 个不同事件的问题。
当然,在这种情况下 Form1
class 将不知道哪个脚本正在更新文本,但在您的情况下这可能无关紧要。
另请注意,如果您 确实 使 scriptX
class 非静态,您可能会再次 运行 进入问题必须多次订阅。但这更容易处理,因为在那种情况下您似乎肯定会使用基 class,因此很容易将 "subscribe, run script, unsubscribe" 逻辑概括为辅助方法。