如何与另一个类的表单控件进行通信?

时间:2014-03-13 16:52:23

标签: c# .net winforms visual-studio

对C#来说有点新鲜,接近我之外的事情。道歉。

我在Visual Studio C#Express中有一个Windows窗体应用程序,使用默认类VS spawns。我想从声明它的默认Form1以外的类开始和停止Marquee样式progressBar。 这些看起来非常困难,我相信我错过了一些重要的东西。

我的项目具有Visual Studio自动生成的常用类: Form1.cs,Form1.Designer.cs,Program.cs。 我添加了想要谈论加载栏的 myClass.cs 。 我使用设计器将 progressBar1 栏添加到我的表单中,设置样式:选框。

Form1.cs ' Form()构造函数,我写

this.progressBar1.Visible = false;

这很有效。 Intellisense'看到' progresBar1。 Form1.cs 中的代码可以查看和控制 Form1.Designer.cs 中声明的 progressBar1 。 这对我来说很有意义。

但是需要启动和停止加载栏的函数必须存在于 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。中键入代码时, progresBar1 事实上,智能感知不能看到' myClass.cs。 Form1.cs 中的任何内容 Form1 中添加的公共属性或函数不会对intellisense可见。 这对我来说没有意义,我很困惑。 这似乎是你想要经常轻松做的事情。

某些搜索表明阻止外部访问表单控件是设计使然。与“解耦”有关的事情'来自GUI代码的逻辑代码,这在理论上是有道理的。显然,有一种预期的方法,但很难找到一个明确的例子。我只能找到完全在声明它们的Forms中控制的loadbars的示例,或者简化关于创建和注册事件或使用Invoke或其他我不太了解的事情的半示例。有许多明显的解决方案,但我无法看到的任何解决方案都明确适用于我,或者我能够以我的无知实施。

如果我的表格是一个实例,我想我可以做到。 [编辑]不。实例与否, Form1 控件永远不会暴露在 Form1.cs 之外

那么,如何以正确的方式从声明它的默认 Form1 以外的类开始和停止Marquee样式progressBar? 某处有明确有用的例子吗?

3 个答案:

答案 0 :(得分:1)

您无法以这种方式访问​​您的媒体资源:

Form1.progressBar1

因为Form1是一个类型(不是实例化对象)。您可以使用此方法访问的唯一方法或属性必须标记为static

要回答关于如何沟通的问题,您可能希望使用您提到的事件方法。首先,您需要在逻辑类中使用一个事件:

public event Action<int> UpdateProgress;

这就像一个函数一样被调用:

if (UpdateProgress != null)
   UpdateProgress(10);

这使用Action泛型委托声明一个新事件,这意味着listen函数必须返回void并将一个int作为参数。

然后在您的表单代码中,您将拥有:

MyClass logic = new MyClass();
private void SomeFunction
{       
    logic.UpdateProgress += UpdateProgressBar;
}

private void UpdateProgressBar(int newProgress)
{
    progressBar1.BeginInvoke(new Action(() =>
    {
       progressBar1.Value = newProgress;
    }));
}

这将创建逻辑类的新实例,并分配函数&#34; UpdateProgressBar&#34;每当您的逻辑类引发UpdateProgressBar事件时调用。该函数本身使用Dispatcher.BeginInvoke,因为您的逻辑类可能没有在UI线程上运行,并且您只能从该线程执行UI任务。

这里有很多事情,所以如果我能为你澄清一切,请告诉我!

答案 1 :(得分:0)

我会创建一个具有与您的表单匹配的属性的模型,然后传递它。

所以你要创建一个像这样的新课......

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

我建议第一种方式,你可以控制传递的数据

答案 2 :(得分:0)

您正尝试访问类型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就像任何其他类一样。您可以使用其他课程完成几乎所有操作。因此,只要您不使用多线程,与表单进行通信与与其他对象的通信没有什么不同。