2017-09-01 28 views
-2

在網上搜索了兩天而沒有找到可以正確理解的解決方案之後,我必須在這裏請求答案。從窗體訪問班級,反之亦然

我有一個windows窗體應用程序,寫在vb.net和工作正常。我已決定重寫本中,我想不會是太大的問題,但是C#...

我在項目兩類:

FormJobs & AppJobs

FormJobs包含的方法和以某種方式修改表單的函數。

AppJobs包含所有其他方法(檢查,掃描等)的方法和函數。

在我的主窗體(FrmStart)上,On_load事件使用AppJobs中的函數來檢查網絡是否啓動(public bool CheckNetConnection),然後檢查以確保存在根保存文件夾(public void CheckRoot)。

如果CheckNetConnection爲false或CheckRoot不存在,則FormJobs類中的某個方法將某些按鈕設置爲禁用,某些標籤顯示錯誤信息以及設置窗體高度。

上述工作在VB.net,但我不斷收到StackOverflowException或NullReferenceException與C#代碼。

我知道異常的原因是因爲兩個類和窗體都在不斷調用對方,所以我知道我需要刪除這段代碼,但我不知道如何讓每個類和窗體訪問對方。這顯然是不好的設計,因爲我剛剛開始學習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); 
       } 

      } 

     } 

    } 
} 

FormJobs代碼

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; 

     } 


} 
+2

https://stackoverflow.com/help/mcve – mjwills

+1

請與我們分享您的不工作的C#代碼。我很確定這個錯誤是在你的實現中,而不是你在這裏爲我們描述的邏輯。 – Pio

+1

無法看到代碼就無法修復代碼。至於一般的佈局,我不會讓'FormJobs' **改變**形式,而是暴露一個狀態(例如'bool DisableAllButtons'),並且擁有每一種形式(在創建時,或者在接收到一個事件的狀態改變)**觀察**暴露的狀態並相應地進行調整。隨意改變對方**是近乎不可維護的代碼的溫牀。根據他們的環境,自己的班級/表格可以自行更改**,而且更易於管理。 – Flater

回答

1

你的問題的原因之一是,每個人都在改變你的StartForm。除此之外,這意大利麪很難理解,如果你的Startform改變了,它肯定無助於你的課程可重用和可維護。

在我看來,AppJobs是用來決定窗體應該是什麼樣子的(例如它決定StartForm應該改變高度),而FormJobs執行改變這個高度所需的計算。 StartForm顯然只是讓每個人都對他做出改變。

更好的設計是StartForm不會要求AppJobs更改其大小,並詢問操作員是否應生成文件夾。相反,如果要求appJobs提供建議:「你認爲我應該擁有哪個高度」。之後,它可能會問FormJobs:

FormJobs應該信任StartForm,它已收集到的有關如何StartForm應該看起來像正確的信息「請根據本規範調整我的高度」。 FormJobs不應該詢問AppJobs的任何信息:「嗨AppJobs,StartForm要求我將其外觀改爲某些規範,但我不確定StartForm是否已正確完成其工作,請告訴我這些規範是否正確,然後給我一些缺少的信息「)

正確劃分任務將是:

  • AppJobs指定根據其內部狀態(AO爲approot,和某些文件夾的存在)
  • StartForm是任何StartForm的格式顯示所有項目的人。他決定詢問誰的規格,以及如何處理退回的規格。他也是唯一一個與運營商溝通的人
  • FormJobs是一個顯然知道StartForm所有元素的類。如果您只有一種類型StartForm,則Appjobs應該是Startform類的一部分。如果您認爲可能有幾個不同的類,所有類都應該被類似地操作,那麼不應該從FormJobs類派生所有這些StartForm類嗎?

不管怎麼說,重新設計沒有大家造成操縱StartForm

顯然有依據爲approot的StartForm佈局數量有限,defaultDevice等你似乎缺少一些「別人」的話,那麼這是你的後列表可能不準確。仍然會有這樣的想法:

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,而不是按位或?

而我使用的語句如if (a)而不是if(a=true) a C#布爾值是一個真正的布爾值,與C和C++中的布爾值相反。

類的各種形式,應該是能夠根據所請求的佈局是佈局包含類似功能的

這取決於一點,你是否決定要讓它成爲一個基類的StartFormStartForm本身。如果你希望它處理的具有所需的控制每一個窗體類,可以考慮使用的接口:

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

這樣你就可以設置任何形式的具有這些標籤和按鈕的大小,即使他們有不同的名稱比您使用的字符串。

但是,如果您只想要規模StartForm,那麼這應該是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'是什麼,只是它具有需要改變的標籤和按鈕等。

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作用。另外:因爲我使用類型而不是字符串,你可以確定我不能像處理按鈕那樣處理標籤。我不能意外地嘗試按下標籤。當您使用字符串來標識要佈置的項目時,可以輕鬆完成的一件事。

+0

感謝您的全面解釋。它也是Pio下面的答案,讓我根據這裏的建議重新設計應用程序。現在我已經將所有的代碼都移到了AppJobs類中,並且更改了所有的代碼,因此可以重用。再次非常感謝所有的幫助 – Gazza

1

擴展評論:您剛纔刪除您FormJobs和AppJobs類new部分。 將代碼留在FormJobs類中,例如:AppJobs appObj;
然後在你的主表單中創建一個FormJobs obj和一個AppJobs obj並設置它的屬性。
I.e.在主要形式有:

AppJobs appObj = new AppJobs(); 
FormJobs formObj = new FormJobs(); 
formObj.appObj = appObj; 

芹苴我必須說,我不喜歡這種方法,你用這個取...

你應該想到的另一種方式,或者至少重構你的代碼是FormJobs不需要AppJobs方法,反之亦然,所有對FormJobs和AppJobs的調用都來自主窗體。

相關問題