[英]How do I communicate with a control of a Form from another class?
C#的一些新知识,超越了我。 抱歉的长度。
我在Visual Studio C#Express中有一个Windows窗体应用程序,使用默认类VS生成。 我想从声明它的默认Form1之外的其他类中启动和停止Marquee风格的progressBar。 这些似乎非常困难,我确信我错过了一些重要的东西。
我的项目具有Visual Studio自动生成的常规类: Form1.cs,Form1.Designer.cs,Program.cs。 我添加了myClass.cs ,它想谈谈加载栏。 我使用设计器将ProgressBar1栏添加到表单中,设置了Style:Marquee。
在Form1.cs的Form()构造函数中,我编写了
this.progressBar1.Visible = false;
这可行。 Intellisense“看到” progresBar1。 在Form1.cs代码可以查看和控制progressBar1在Form1.Designer.cs声明。 这对我来说很有意义。
但是需要启动和停止加载栏的功能必须存在于myClass.cs中 。 我希望能够在myClass.cs中进行这样的编码:
public void myFunction(){
Form1.progressBar1.visible=true
//do stuff that takes a bit of time
Form1.progressBar1.visible=false
}
这是行不通的。 在myClass.cs中键入代码时,Intellisense无法“查看” progresBar1 。 实际上,智能感知无法从myClass.cs内部“查看” Form1.cs中的任何内容。 智能感知不会看到添加到Form1的公共属性或功能。 这对我来说没有意义,我很困惑。 这似乎是您想要经常且轻松地执行的操作。
一些搜索表明,这种对窗体控件的外部访问的阻止是设计使然。 从原理上讲,这与将逻辑代码与GUI代码``分离''有关,因此显然存在一种预期的方法,但很难找到一个清晰的例子。 我只能找到完全在声明它们的窗体中控制的负载条的示例,或者关于创建和注册事件或使用Invoke或其他我所知甚少的简短示例。 有很多明显的解决方案,但我无知的解决方案对我来说显然无济于事。
如果我的Form是实例,我想可以做到。 [编辑]不。 是否实例化, Form1控件永远不会暴露在Form1.cs外部
因此,如何以正确的方式从声明默认Form1的类之外的其他类中启动和停止Marquee风格的progressBar? 在某个地方有一个清晰有用的例子吗?
您无法通过以下方式访问您的媒体资源:
Form1.progressBar1
因为Form1是一种类型(不是实例化的对象)。 使用此方法可以访问的唯一方法或属性必须标记为static
。
要回答有关如何交流的问题,您可能希望使用您提到的事件方法。 首先,您需要在逻辑类中创建一个事件:
public event Action<int> UpdateProgress;
就像一个函数一样被调用:
if (UpdateProgress != null)
UpdateProgress(10);
这使用Action泛型委托声明了一个新事件,这意味着侦听函数必须返回void并将int作为参数。
然后在表单代码中,您将拥有:
MyClass logic = new MyClass();
private void SomeFunction
{
logic.UpdateProgress += UpdateProgressBar;
}
private void UpdateProgressBar(int newProgress)
{
progressBar1.BeginInvoke(new Action(() =>
{
progressBar1.Value = newProgress;
}));
}
这将创建逻辑类的新实例,并在逻辑类引发UpdateProgressBar事件时分配要调用的函数“ UpdateProgressBar”。 该函数本身使用Dispatcher.BeginInvoke,因为您的逻辑类可能不在UI线程上运行,并且您只能从该线程执行UI任务。
这里发生了很多事情,所以请让我知道是否可以为您澄清任何事情!
我将创建一个具有与您的表单匹配的属性的模型,并将其传递给周围。
所以你会像这样上新课...
using Windows.Forms;
public class Form1Model {
public ProgressBar progressBar { get; set; }
}
然后,当您要转到另一个拥有该函数的类时,可以创建一个Form1Model实例,填充它,然后调用您的函数
var fm = new Form1Model {
progressBar = this.progressBar1;
};
otherClass.MyFunction(fm);
现在您必须更改功能以接受新模型
public void MyFunction(Form1Model fm){
// do stuff
}
另一个选择是仅使函数采用表单的实例,而不创建模型,但是您将传递很多可能不关心的额外位
public void MyFunction(Form1 form){
// do stuff
}
然后在表单上,您将像这样调用函数
otherClass.myFunction(this);
我建议在第二种方法中使用第一种方法,您可以控制正在传递的数据
您正在尝试访问Form1
类型而不是表单实例。 我将向您展示如何访问下面的实例。
我假设Form1
是只要应用程序运行就保持打开状态的应用程序主窗体。 当您创建WinForms应用程序时,VS在Program.cs
创建以下代码:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
使您的主窗体可在整个应用程序中访问的一种简单方法是通过公共静态属性对其进行访问。 像这样更改代码
static class Program
{
public static Form1 MainForm { get; private set; }
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new Form1();
Application.Run(MainForm);
}
}
在Form1
创建一个显示进度条可见性的属性:
public bool IsProgressBarVisible
{
get { return this.progressBar1.Visible; }
set { this.progressBar1.Visible = value; }
}
现在,您可以使进度条在程序的任何部分可见,如下所示:
Program.MainForm.IsProgressBarVisible = true;
访问主表单的另一种方法是,因为它总是作为第一个表单打开的:
((Form1)Application.OpenForms(0)).IsProgressBarVisible = true;
但是,由于OpenForms
返回Form
,因此它要求将表单转换为正确的类型。
并且不要忘记: Form
就像其他任何类一样,只是一个类。 您几乎可以完成其他班级可以做的所有事情。 因此,与表单进行通信与与其他对象进行通信并没有很大不同,只要您不使用多线程即可。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.