2016-11-28 66 views
0

我有一個WinForms GUI中的幾個不同的控件必須全部彼此同步:我有兩個文本框在不同的單位顯示相同數量和2個自定義控件顯示數量圖形化爲舊式模擬量規。更改文本框中的值或自定義控件的值會導致通過USB將新值寫入硬件。同步VB.net中的多個事件的多個控件

我不想要的是當更改一個控件時,將多個USB消息發送到硬件。然而,當一個控件的事件處理程序更新其他三個控件時,它們的事件處理程序也會運行。這是兩個方面,到目前爲止我已經解決了這個問題,但我希望有一個更好的東西:

  1. 起初,我只是做了一個全球性的標誌每套控制。當事件處理程序運行時,它會檢查標誌,如果它被設置,它立即存在。如果沒有設置標誌,則事件處理程序會設置它,然後更新其他3個控件,這些控件的事件處理程序在執行時不應該執行任何操作,因爲現在已設置全局標誌。

  2. 現在我使用AddHandler和RemoveHandler語句關閉/打開其他3個控件的事件處理程序,當我在第一個事件處理程序中更新它們時。這樣可以阻止其他事件處理程序在第一時間甚至開始執行。

我的第一個解決方案很簡單,但感覺就像一個巨大的黑客攻擊。第二種解決方案意味着我的所有事件處理程序都需要爲AddHandler/RemoveHandler語句添加6條額外的行。

我希望有更好的東西,我從來沒有夢想過(也許一些固有的方式告訴vb.net控件連接?),但谷歌搜索尚未幫助我。我很感激我能從你那裏得到的任何幫助!

回答

1

您絕對只需要一個地方進行更新。
你沒有提到你有什麼樣的UI(Winforms,WPF - 假設你在談論桌面應用程序)。

我建議使用MVVM風格 - 它將適用於Winforms和WPF。

Public Class USBViewModel 
    Implements INotifyPropertyChanged 

    Private _Quantity As Integer 
    Public Property Quantity As Integer 
     Get 
      Return _Quantity 
     End Get 
     Set(value As Integer) 
      If value = _Quantity Then Exit Property 
      ' Here you can update value to the USB 
      _Quantity = value 
      RaisePropertyChanged() 
     End Set 
    End Property 

    #Region "INotifyPropertyChanged" 

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

    Private Sub RaisePropertyChanged(<CallerMemberName> Optional propertyName As String = Nothing) 
     RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) 
    End Sub 

    #End region 

End Class 

然後,您可以將一個(相同)USBViewModel實例綁定到您的控件。
您可以創建FormatParse事件處理程序,以將原始單位轉換爲要顯示和返回的單位。
對於的WinForms例如文本框可以界定如下:

Public Class YourForm 
    Private ReadOnly _ViewModel As USBViewModel 
    Public Sub New() 
     InitializeComponents() 

     _ViewModel = new USBViewModel() 

     var unitOneBunding = new Binding("Text", _ViewModel, "Quantity", True); 
     unitOneBunding.Format += bindUnitOne_Format; 
     unitOneBunding.Parse += bindUnitOne_Parse; 

     TextBoxUnitOneQuantity.DataBindings.Add(unitOneBunding); 
    End Sub 

    private void bindUnitOne_Format(object sender, ConvertEventArgs e) 
    { 
     int originalUnitValue = (int)e.Value; 
     int unitOneValue = ConvertToUnitOne(originalUnitValue); 
     e.Value = unitOneValue; 
    } 

    private void bindUnitOne_Parse(object sender, ConvertEventArgs e) 
    { 
     int unitOneValue = (int)e.Value; 
     int originalUnitValue = ConvertToOriginalUnit(unitOneValue); 
     e.Value = originalUnitValue; 
    } 
End Class 

自定義控件你可以通過同一實例的自定義控件的構造,有其綁定到相同的屬性。

此解決方案基於INotifyPropertyChanged和數據綁定。
當您使用數據綁定控件時,將「偵聽」INotifyPropertyChanged事件,並在值更改時自動更新。
在用戶更新控件的情況下,控件將調用有界屬性的setter。

+0

我修改了我的文章,指定我正在製作Winforms應用程序。 DataBindings似乎是我在處理這個問題之前就無知的工具?谷歌搜索數據綁定有幫助。但是,我並不立即看到不同綁定控件如何知道在不同單元中顯示相同的值。 – BigBobby

+0

@BigBobby,你可以使用'DataBinding.Format'和'DataBInding.Parse'事件將一個單位轉換爲另一個單位,查看我更新的答案 – Fabio

1

用級聯事件處理程序綁定節點非常容易。我建議有一個「保存更改」按鈕,只有當該按鈕被點擊時纔會發送USB消息。

對於您的文本框,您可以使用與TextChanged不同的事件。

Private Sub TextBox1_Validating(sender As Object, e As CancelEventArgs) Handles TextBox1.Validating 
    If Val(TextBox1.Text) < 0 Then 
     e.Cancel = True 'don't allow negative numbers 
    Else 
     TextBox2.Text = (Val(TextBox1.Text)/10).ToString 
    End If 
    End Sub 

    Private Sub TextBox2_Validating(sender As Object, e As CancelEventArgs) Handles TextBox2.Validating 
    If Val(TextBox2.Text) < 0 Then 
     e.Cancel = True 'don't allow negative numbers 
    Else 
     TextBox1.Text = (Val(TextBox2.Text) * 10).ToString 
    End If 
    End Sub 

如果你真的想實時單位換算,那麼另一種選擇是:例如,如果你使用Validating,您可以提交和更新其它文本框不會觸發無限循環前檢查輸入值檢查ActiveControl

Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged 
    If ActiveControl Is TextBox1 Then 
     TextBox2.Text = (Val(TextBox1.Text)/10).ToString 
    End If 
    End Sub 

    Private Sub TextBox2_TextChanged(sender As Object, e As EventArgs) Handles TextBox2.TextChanged 
    If ActiveControl Is TextBox2 Then 
     TextBox1.Text = (Val(TextBox2.Text) * 10).ToString 
    End If 
    End Sub