C# 从窗体访问类,反之亦然

C# 从窗体访问类,反之亦然,c#,winforms,visual-studio,C#,Winforms,Visual Studio,在网上搜寻了两天,但没有找到一个我能正确理解的解决方案后,我不得不在这里问一个答案 我有一个用vb.net编写的windows窗体应用程序,运行良好。我决定用c语言重写这篇文章,我认为这不会有太大问题,但是 我在项目中有两门课: FormJobs和AppJobs FormJobs包含以某种方式修改表单的方法和函数 AppJobs包含用于其他一切(检查、扫描等)的方法和函数 在我的主窗体(FrmStart)上,On_load事件使用AppJobs中的函数检查网络是否正常(public bool C

在网上搜寻了两天,但没有找到一个我能正确理解的解决方案后,我不得不在这里问一个答案

我有一个用vb.net编写的windows窗体应用程序,运行良好。我决定用c语言重写这篇文章,我认为这不会有太大问题,但是

我在项目中有两门课:

FormJobs和AppJobs

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

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

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

如果CheckNetConnection为false或CheckRoot不存在,则FormJobs类中的方法会将一些按钮设置为禁用,将一些标签设置为显示错误信息,并设置窗体的高度

上面的代码在VB.net中运行,但我一直在使用C#代码获取StackOverflowException或NullReferenceException

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

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

FrmStart代码

AppJobs Appjobs = new AppJobs();

private void FrmStart_Load(object sender, EventArgs e)
    {

                    KeyPreview = true;

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

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

            }

        }

    }
}
格式作业代码

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;

        }


}

扩展注释:只需删除FormJobs和AppJobs类中的
new
部分。 将代码保留在FormJobs类中,如:
AppJobs Appbj
然后在主窗体中,在某个点创建FormJobs对象和AppJobs对象,并设置其属性。
即主要形式:

AppJobs appObj = new AppJobs(); 
FormJobs formObj = new FormJobs(); 
formObj.appObj = appObj;
虽然我必须说我不喜欢你在这方面采取的方法


您应该考虑另一种方法,或者至少重构您的代码,使FormJobs不需要AppJobs方法,反之亦然,所有对FormJobs和AppJobs的调用都来自主窗体。

问题的原因之一是每个人都在更改您的
StartForm
。除此之外,如果
Startform
发生了变化,那么这条意大利面条就很难理解,当然也无助于使类可重用和可维护

在我看来,
AppJobs
旨在决定表单的外观(例如,它决定
StartForm
应更改高度),而
FormJobs
执行更改此高度所需的计算
StartForm
显然只是允许每个人对他进行更改

更好的设计是
StartForm
不会要求
AppJobs
更改其大小,并询问操作员是否应生成文件夹。相反,如果你应该询问appJobs的建议:“你认为我应该有多高?”。之后,它可以问FormJobs:“请根据此规格调整我的身高”

FormJobs
应该相信
StartForm
已经收集了有关
StartForm
应该是什么样子的正确信息
FormJobs
不应询问
AppJobs
任何信息:“嘿,AppJobs,StartForm要求我将其外观更改为某些规格,但我不确定StartForm是否正确完成了其工作。请告诉我这些规格是否正确,并提供一些缺少的信息”)

正确的任务划分是:

  • AppJobs根据其内部状态(a.o.Approt和某些文件夹的存在)指定任何
    StartForm
    的格式
  • StartForm
    显示所有项目。他决定向谁索取规格,以及如何处理返回的规格。他也是唯一一个与运营商沟通的人
  • FormJobs
    是一个显然从
    StartForm
    中知道所有元素的类。如果只有一种类型的
    StartForm
    ,那么
    Appjobs
    应该是
    StartForm
    类的一部分。如果您认为可能有几个不同的
    Startform
    类,它们都具有相同的元素,应该进行类似的操作,那么这些
    Startform
    类难道不应该从
    FormJobs
    类派生出来吗
无论如何,重新设计时不要让每个人都操纵
StartForm

显然,根据Approt、defaultDevice等的不同,StartForm的布局数量有限。在if之后,您似乎缺少了一些“其他”,因此此列表可能不准确。但你还是会有这样的想法:

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
是唯一一个知道它说什么语言以及在请求某个布局时该做什么的人

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

和我使用语句如<代码>(A)< /COD>而不是<代码>(如果(a=true)< /COD> C是布尔布尔,是与C和C++中的Booleans相矛盾的。< /P> 应该能够根据请求的布局进行布局的各种表单的类包含与

这取决于你是否决定让它成为bas
public Interface IStartForm
{
    public int Height {get; set;}
    public Label LabelNoRoot {get;}
    public Label LabelNoDevice {get; }
    public Button BtnTickets {get;}
    ...
public SetHeight(StartFormLayout layout, IStartForm startForm)
{
    switch (layout)
    {
        case StartFormLayout.DefaultDevice0:
            if (startForm.MenuStrip.Visible)
            {
                startForm.Height = ...;
                startForm.LabelNoRoot.Location = ...
                // etc
            }
            else
            {
               ...
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)
    }