从表单访问类,反之亦然 [英] Accessing class from form and vice-versa

查看:38
本文介绍了从表单访问类,反之亦然的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在互联网上搜索了两天并没有找到我能正确理解的解决方案后,我不得不在这里询问答案.

After hunting the internet for two days and not finding a solution that I can understand properly I have to ask on here for an answer.

我有一个用 vb.net 编写的 Windows 窗体应用程序并且运行良好.我决定用 c# 重写它,我认为这不会有太大问题,但是...

I have a windows forms application that was written in vb.net and works fine. I have decided to rewrite this in c# which I thought wouldn't be too much of a problem but ...

我在项目中有两个类:

FormJobs &应用作业

FormJobs & AppJobs

FormJobs 包含以某种方式修改表单的方法和函数.

FormJobs contains methods and functions that modify the forms in some way.

AppJobs 包含其他一切(检查、扫描等)的方法和函数.

AppJobs contains methods and functions for everything else (Checks,Scanning and so forth).

在我的主窗体 (FrmStart) 上,On_load 事件使用来自 AppJobs 的函数来检查网络是否已启动(public bool CheckNetConnection),然后检查以确保根保存文件夹存在(public void CheckRoot).

On my main form (FrmStart) the On_load event uses a function from AppJobs to check that the network is up (public bool CheckNetConnection) and then Checks to make sure that the root save folder exists (public void CheckRoot).

如果 CheckNetConnection 为 false 或 CheckRoot 不存在,则 FormJobs 类中的一个方法将一些按钮设置为禁用,一些标签显示有关出错的信息并设置表单的高度.

If CheckNetConnection is false or CheckRoot does not exist then a method in the FormJobs class sets some buttons to disabled, some labels to display information as to what has gone wrong and also sets the height of the form.

以上在 VB.net 中有效,但我不断收到带有 C# 代码的 StackOverflowException 或 NullReferenceException.

The above works in VB.net but I keep getting a StackOverflowException or NullReferenceException with the C# code.

我知道异常的原因是因为这两个类和表单都一直在互相调用,所以我知道我需要删除此代码,但我不确定如何让每个类和表单相互访问.这显然是糟糕的设计,因为我刚刚开始学习 C#,因此我们将不胜感激.

I know the reason for the Exceptions is because the two classes and the form all keep calling each other so I know that I need to remove this code but I am not sure how to let each class and the form access each other. It is obviously bad design as I`m just starting to learn C# so any help on this would be much appreciated.

但我的主要问题是:-如何获取访问多个类的表单?允许类相互访问?让类对表单进行更改?

But my main questions are:-How do I get a form to access multiple classes? Allow the classes to access each other? Let the classes make changes to a form?

开始代码

AppJobs Appjobs = new AppJobs();

private void FrmStart_Load(object sender, EventArgs e)
    {

                    KeyPreview = true;

        if (Appjobs.CheckNetConnection(this) == true)
        {
            Appjobs.CheckRoot(this);
        }

应用程序代码

public class AppJobs
{

    FormJobs Formjobs = new FormJobs();

    public string AppRoot = Properties.Settings.Default.DefaultFolder;
    public string DefaultDevice = Properties.Settings.Default.DefaultScanner;
    public bool NoDirectory = false;

    DialogResult MsgBoxQuestion;

    public bool CheckNetConnection(Form StartForm)
    {

        IPHostEntry ServerIP = new IPHostEntry();
        bool ConnectedToServer = false;
        string CurrentRoot = "MyServer";

        if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
        {
            try
            {
                IPHostEntry DNSTest = Dns.GetHostEntry(CurrentRoot);
                if (DNSTest.AddressList.Length > 0)
                {
                    ConnectedToServer = true;
                }
                else
                {
                    ConnectedToServer = false;

                }


            }
            catch (System.Net.Sockets.SocketException ex)
            {
                ConnectedToServer = false;
            }
        }

        return ConnectedToServer;

    }

    public void CheckRoot(Form StartForm)
    {
        if (string.IsNullOrEmpty(AppRoot))
        {
            Formjobs.SetHeight(StartForm);
            return;


        }else if(AppRoot == "0")
        {
            Formjobs.SetHeight(StartForm);
            return;
        }
        else
        {
            if ((!Directory.Exists(AppRoot)))
            {
                NoDirectory = true;
                MsgBoxQuestion = MessageBox.Show(AppRoot + " is set, but the directory does not exist." + Environment.NewLine
                    + Environment.NewLine + "Would you like to create the folder now?", "Root folder missing", MessageBoxButtons.YesNo);
                if (MsgBoxQuestion == DialogResult.Yes)
                {
                    Directory.CreateDirectory(AppRoot);
                    NoDirectory = false;
                }
                else
                {
                    MessageBox.Show("You will not be able to use this program until you create a root folder.", "No root folder selected",MessageBoxButtons.OK);
                }

            }

        }

    }
}

FormJobs 代码

FormJobs Code

public class FormJobs
{

    AppJobs Appjobs = new AppJobs();

    public void SetHeight(Form StartForm)
    {

        if (Appjobs.AppRoot == null | Appjobs.AppRoot == "0") {

if (Appjobs.DefaultDevice == null | Appjobs.DefaultDevice == "0") {

    if (StartForm.Controls["MenuStrip1"].Visible == true) {
        StartForm.Height = 167;
        StartForm.Controls["LblNoRoot"].Visible = true;
        StartForm.Controls["LblNoRoot"].Location = new Point(0, 24);
        StartForm.Controls["LblNoRoot"].Text = "There is no root folder selected. Please select a root folder to continue.";
        StartForm.Controls["LblNoDevice"].Visible = true;
        StartForm.Controls["LblNoDevice"].Location = new Point(0, 48);
        StartForm.Controls["LblNoDevice"].Text = "There is no default device selected. Please select a default device to continue.";
        StartForm.Controls["BtnOkTickets"].Enabled = false;
        StartForm.Controls["BtnQueryTickets"].Enabled = false;
        StartForm.Controls["BtnSearch"].Enabled = false;

    }else

        {
        StartForm.Height = 147;
        StartForm.Controls["LblNoRoot"].Visible = true;
        StartForm.Controls["LblNoRoot"].Location = new Point(0, 9);
        StartForm.Controls["LblNoRoot"].Text = "There is no root folder selected. Please select a root folder to continue.";
        StartForm.Controls["LblNoDevice"].Visible = true;
        StartForm.Controls["LblNoDevice"].Location = new Point(0, 33);
        StartForm.Controls["LblNoDevice"].Text = "There is no default device selected. Please select a default device to continue.";
        StartForm.Controls["BtnOkTickets"].Enabled = false;
        StartForm.Controls["BtnQueryTickets"].Enabled = false;
        StartForm.Controls["BtnSearch"].Enabled = false;

        }


}

推荐答案

问题的原因之一是每个人都在更改您的 StartForm.除此之外,这个意大利面让人难以理解,如果您的 Startform 发生变化,它肯定无助于使您的类可重用和可维护.

One of the causes of your problems is that everyone is changing your StartForm. Apart from that this spaghetti makes it difficult to understand, it certainly doesn't help to make your classes reusable and maintainable if your Startform changes.

在我看来,AppJobs 是用来决定表单应该是什么样子的(例如它决定 StartForm 应该改变高度),而 FormJobs 执行更改此高度所需的计算.StartForm 显然只是允许让每个人对他进行更改.

It seems to me, that AppJobs is meant to decide what the form should look like (for instance it decides that the StartForm should change height), while FormJobs performs the calculations needed to change this height. StartForm apparently is just allowing to let everyone make changes to him.

更好的设计是 StartForm 不会要求 AppJobs 更改其大小,也不会询问操作员是否应生成文件夹.相反,如果应该询问 appJobs 的建议:你认为我应该有什么高度".之后它可以询问 FormJobs:请根据此规范调整我的高度"

A better design would be that StartForm would not ask AppJobs to change its size, and to ask the operator whether a folder should be generated. Instead if ought to ask appJobs for advise: "Which height do you think I should have". after that it could ask FormJobs: "Please adjust my height according to this specification"

FormJobs 应该相信 StartForm 它已经收集了关于 StartForm 应该是什么样子的正确信息.FormJobs 不应该向 AppJobs 询问任何信息:嘿 AppJobs,StartForm 要求我将其外观更改为某些规范,但我不确定 StartForm 是否完成了它的工作正确.请告诉我这些规格是否正确,并给我一些缺失的信息")

FormJobs should trust StartForm that it has gathered the correct information about how a StartForm ought to look like. FormJobs should not ask AppJobs for any information: "Hey AppJobs, StartForm asked me to change its appearance to certain specifications, but I'm not certain whether StartForm has done its job correctly. Please tell me if these specifications are correct, and give me some missing information")

正确的任务划分是:

  • AppJobs 根据其内部状态(a.o. AppRoot 和某些文件夹的存在)指定任何 StartForm 的格式
  • StartForm 是显示所有项目的那个.他决定向谁索取规范,以及如何处理返回的规范.他也是唯一一个和运营商沟通的人
  • FormJobs 是一个显然知道 StartForm 中所有元素的类.如果您只有一种 StartForm,那么 Appjobs 应该是 Startform 类的一部分.如果您认为可能有几个不同的 Startform 类,它们都具有相同的元素,应该以类似的方式进行操作,那么所有这些 StartForm 类不应该从 >FormJobs 类?
  • AppJobs specifies the format of any StartForm according to its internal state (a.o. AppRoot, and existence of certain folders)
  • StartForm is the one who displays all items. He decides who to ask for specifications, and what to do with the returned specifications. He is also the only one who communicates with operators
  • FormJobs is a class that apparently knows all elements from a StartForm. If you will only have one type of StartForm, then Appjobs should be part of the Startform class. If you think there might be several different Startform classes, all with the same elements that ought to be manipulated similarly, shouldn't all these StartForm classes be derived from a FormJobs class?

无论如何,重新设计,不要让每个人都操作StartForm

Anyway, redesign without everyone causing to manipulate StartForm

显然,StartForm 布局的数量有限,具体取决于 AppRoot、defaultDevice 等.您似乎在 if 之后遗漏了一些else",因此此列表可能不准确.你还是会明白:

Apparently there are a limited number of StartForm layouts depending on AppRoot, defaultDevice etc. You seem to be missing some "else" after your if, so this list might not be accurate. Still you will get the idea:

enum StartFormLayouts
{
    DefaultDevice0,
    AppRoot0,
    Other,        
}

// class that specifies the layout of any startform
class AppJobs
{
    private bool IsAppRoot0 
    {
        get{return Appjobs.AppRoot == null || Appjobs.AppRoot == "0";}
    }
    private bool IsDefaultDevice0
    {
        get{return Appjobs.DefaultDevice == null || Appjobs.DefaultDevice == "0";}
    }

    public StartFormLayoug GetPreferredLayout()
    {
         if (this.IsAppRoot0)
         {
             if (this.IsDefaultDevice)
             {
                  return StartFormLayout.DefaultDevice0;
             }
             else
                  return StartFormLayout.AppRoot0;
          }
          else
          {
              return StartFormLayout.Other;
          }
    }

    public bool ShouldAskDirectoryCreation()
    {
        return (!this.IsAppRoot0 && !Directory.Exists(AppRoot));
    }
}

注意这个类不需要StartForm,也不需要AppJobs.它可以与任何想知道它是否应该要求 DirectoryCreation 的类一起工作.由于它也不会说任何语言,即使是中文 StartForm 也可以使用它.毕竟,StartForm 是唯一知道它说的是什么语言以及在请求某种布局时要做什么的人.

Note that this class doesn't need StartForm, nor AppJobs. It could work with any class that wants to know if it should ask for DirectoryCreation. Since it also does not speak any language, even a Chinese StartForm could use it. After all, the StartForm is the only one who knows what language it speaks and what to do if a certain layout is requested.

此外,您是否注意到我使用双 || 来使用布尔 OR 而不是按位或?

Furthermore, did you notice that I used a double || to use a Boolean OR instead of a bitwise or?

我使用像 if (a) 这样的语句而不是 if(a=true) C# 布尔值是真正的布尔值,与 C 和 C++ 中的布尔值相反.

And I use statements like if (a) instead of if(a=true) a C# Boolean is a real Boolean, in contradiction to Booleans in C and C++.

应该可以根据请求的布局进行布局的各种表单的类,包含类似你的功能

The class of all kinds of forms that should be able to be layout according to the requested layout contains the functions similar to your

这取决于您是否决定让它成为 StartFormStartForm 本身的基类.如果您希望它处理具有所需控件的每个表单类,请考虑使用接口:

It depends a bit of whether you decide to let it be a base class of StartForm or StartForm itself. If you want it to handle every form class that has the required controls, consider of using an interface:

public Interface IStartForm
{
    public int Height {get; set;}
    public Label LabelNoRoot {get;}
    public Label LabelNoDevice {get; }
    public Button BtnTickets {get;}
    ...

通过这种方式,您可以设置任何具有这些标签和按钮的表单的大小,即使它们的名称与您使用的字符串不同.

This way you can set the size of any form that has these labels and buttons, even if they have different names than those strings you use.

但同样:如果您只想调整 StartForm 的大小,那么这应该是 StartForm 中的一个函数.

But again: if you ever only want to size StartForm, then this should be a function in StartForm.

public SetHeight(StartFormLayout layout, IStartForm startForm)
{
    switch (layout)
    {
        case StartFormLayout.DefaultDevice0:
            if (startForm.MenuStrip.Visible)
            {
                startForm.Height = ...;
                startForm.LabelNoRoot.Location = ...
                // etc
            }
            else
            {
               ...

注意到由于这种关注点的分离,AppJobs 和 FormJobs 不必相互认识.AppJobs 和 FormJobs 也不必真正知道StartForm"是什么,只需知道它具有需要更改的标签和按钮等.

Noticed that because of this separation of concerns the AppJobs and FormJobs don't have to know each other. AppJobs and FormJobs also don't really have to know what 'StartForm` is, only that it has the labels and buttons etc that it needs to change.

class StartForm : Form, IStartForm
{
    public Label LabelNoRoot {get{return this.label1; } }
    ...

    private void FrmStart_Load(object sender, EventArgs e)
    {
        AppJobs layoutdesigner = new AppJobs(...);
        StartFormLayout layoutdesigner = layouter.GetPreferredLayout();

        FormJobs layouter = new FormJobjs();
        layouter.SetHeight(this)
    }

注意到我的表单没有名为LabelNoRoot"的标签,而是一个 Label1,它应该作为 LabelNoRoot 起作用.另外:因为我使用的是类型而不是字符串,所以您可以确定我无法像处理按钮一样处理标签.我不能偶然尝试按下标签.当您使用字符串来标识要布局的项目时,可以轻松完成某些操作.

Noticed that my form didn't have a label named "LabelNoRoot", but a Label1 that should function as a LabelNoRoot. Also: because I used types instead of string, You can be certain that I can't handle a label as if it was a button. I can't by accident try to press the label. Something that could easily been done when you were using strings to identify the items you want to layout.

这篇关于从表单访问类,反之亦然的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆