2017-04-18 90 views
2

希望得到一些關於從表單上的實例化類捕獲返回消息的最佳實踐建議。最佳實踐 - 表單類接收來自類模塊的消息

在我的表單(form1.vb)中,我有一個標籤,它反映了正在進行的操作,代碼如下。在Form1.vb的

代碼以顯示消息:

Public Sub DisplayMessage(ByVal Msg as String, ByVal Show as Boolean) 
    Application.DoEvents() 
    If Show Then 
     lblShow.Text = Msg 
     lblShow.Refresh() 
    End If 
End Sub 

我已經在三個方法來至今:

  1. 直接型呼叫。在這種情況下的類直接調用窗體的消息例行:

    form1.DisplayMessage("Show This Message", True) 
    


  2. 類中的RaiseEvent。在這種情況下,form1是發送消息的類的Friends WithEvents,並且該類將事件引發到窗體。

    **Declared in Form1.vb** 
    Friend WithEvents Class1 as New Class1  
    
    **Declared in Class1.vb** 
    Public Event SetMessage(ByVal Msg As String, ByVal Show As Boolean) 
    
    **Used in Class1.vb** 
    RaiseEvent SetMessage("Show This Message", True) 
    


  3. 有一個EventArgs類處理該事件。在這種情況下,我們有一個EventArg.vb類,每當我們引發事件時就會實例化。

    **Declared in Form1.vb** 
    Friend WithEvents Class1 as New Class1  
    
    Private Sub class1_DisplayMessage(ByVal Msg As String, ByVal showAs Boolean, ByRef e As ProgressMessageEventArgs) Handles Class1.SetMessage 
        DisplayMessage(Msg, Show) 
    End Sub 
    


**Declared in Class1.vb** 
    Public Event SetMessage(ByVal msg As String, ByVal Show As Boolean, ByRef e As ProgressMessageEventArgs) 

    Protected Sub CaptureMessage(ByVal msg As String, ByVal Show As Boolean) 
     RaiseEvent SetMessage(message, ShowList, New ProgressMessageEventArgs(message)) 
    End Sub 

    **Used in Class1.vb** 
    RaiseEvent CaptureMessage("Show This Message", True) 


**EventArg.vb created to handle ProgressMessageEventArgs class** 
    Public NotInheritable Class ProgressMessageEventArgs 
     Inherits System.EventArgs 
     Public txt As String 

     Public Sub New(ByVal txt As String) 
      MyBase.New() 
      Me.Text = txt 
     End Sub 
    End Class 


情景1看起來是最簡單的,儘管我被告知不要這樣,並被要求提出一個事件。隨着時間的推移,我遇到了場景3,其中涉及到了另一個場景與場景2.

因此,問題是...... 在這三種方法之間,這將是從類中返回消息的「正確」表格?根據場景3,額外的EventArg類是否必要,因爲場景2也可以正常工作?

非常感謝提前。

+0

「最佳實踐」取決於情況。三種形式中的任何一種都可以根據用例進行工作。但是,'Application.DoEvents',默認表單實例和非標準事件簽名不是任何最佳實踐的一部分 – Plutonix

+0

最差的做法:[Application.DoEvents()](http://stackoverflow.com/a/5183623/832052) – djv

+0

你應該真的能夠做'lblShow.Text = Msg',除非你從另一個線程運行。爲什麼'Application.DoEvents'和'Refresh'放在首位? – djv

回答

1

我的回答不是以上所述。考慮這個例子

Public Class Form1 

    Private WithEvents myClass1 As New Class1() 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
     myClass1.CountTo1000() 
    End Sub 

    Private Sub MyClass1_Updated(number As Integer) Handles myClass1.Updated 
     Me.Label1.Text = number.ToString() 
    End Sub 

End Class 

Public Class Class1 

    Public Event Updated(number As Integer) 

    Public Sub CountTo1000() 
     For i = 1 To 1000 
      System.Threading.Thread.Sleep(1) 
      RaiseEvent Updated(i) 
     Next 
    End Sub 

End Class 

你有一種形式,一個類,形式有類的引用(類甚至不知道的形式存在)。您的業​​務邏輯是在課堂上進行的,並且表單用於輸入和顯示信息。 CountTo1000()被直接從窗體中調用,這是不好的,因爲基本上UI線程被放入睡眠1000次,而類正嘗試通過在每次睡眠後提高事件來更新UI。但UI從來沒有時間讓事件發生,即被更新。在Me.Label1.Text = number.ToString()之後放置Application.DoEvents()將允許UI更新。但這是一個糟糕的設計的症狀。不要這樣做。

這裏是多線程

Public Class Form1 

    Private WithEvents myClass1 As New Class1() 

    ' this handler runs on UI thread 
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
     ' make a new thread which executes CountTo1000 
     Dim t As New System.Threading.Thread(AddressOf myClass1.CountTo1000) 
     ' thread goes off to do its own thing while the UI thread continues 
     t.Start() 
    End Sub 

    ' handle the event 
    Private Sub MyClass1_Updated(number As Integer) Handles myClass1.Updated 
     updateLabel(number.ToString()) 
    End Sub 

    ' invoke on UI thread if required 
    Private Sub updateLabel(message As String) 
     If Me.Label1.InvokeRequired Then 
      Me.Label1.Invoke(New Action(Of String)(AddressOf updateLabel), message) 
     Else 
      Me.Label1.Text = message 
     End If 
    End Sub 

End Class 

Public Class Class1 

    Public Event Updated(number As Integer) 

    Public Sub CountTo1000() 
     For i = 1 To 1000 
      System.Threading.Thread.Sleep(1) 
      RaiseEvent Updated(i) 
     Next 
    End Sub 

End Class 

這個簡單的例子示出了如何線程可以創建和運行一些代碼從UI的另一個例子。當這樣做時,如果必須訪問UI控件(Label1),則必須在UI上調用來自非UI線程的任何方法調用。由於Thread.Sleep是在不同於UI線程的線程上完成的,因此該程序可以平穩運行,因爲UI線程無需執行任何操作,並且可以處理其他線程引發的事件,因此不需要Application.DoEvents

我更關注線程,但在這兩個示例中,設計都有一個帶有類的表單,表單知道類,但類不知道表單。更多關於可以看到here

參見:

+0

_現在比Thread更好的選擇:BackgroundWorker_ - 在引入'async-await'之後是過時的選項 – Fabio