2013-01-03 39 views
1

我有一些UI元素在代碼中執行一些特定於UI的工作,然後更新數據上下文中的綁定。在WPF中使用BindingExpression的最佳做法?

WPF元素:

<TextBox Grid.Row="1" 
      Text="{Binding PartNumber, UpdateSourceTrigger=Explicit}" 
      Name="ui_partNumber" 
      FontSize="35" 
      VerticalContentAlignment="Center" /> 
    <Button Grid.Column="1" 
      Grid.Row="1" 
      Content="OK" 
      Click="PartOKClick" 
      FontSize="20" 
      Width="150" /> 

後面的代碼:

/// <summary> 
/// Handle updating the view model with the part number 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e"></param> 
private void PartOKClick(object sender, RoutedEventArgs e) { 

    //Get the textbox's binding expression 
    BindingExpression be = ui_partNumber.GetBindingExpression(TextBox.TextProperty); 

    if (Condition) { 
    //Update part number binding 
    be.UpdateSource(); 

    //Animate to next state 
    InAnimate(ui_partGrid.Name); 
    OutAnimate(ui_whichPartNumber.Name); 
    } 
    else { 
    //Discard the text in the textbox 
    be.UpdateTarget(); 

    //Animate to notification state 
    InAnimate(ui_invalidLocation.Name); 
    } 
} 

在我的ViewModel屬性看起來像:

public string PartNumber{ 
    get { return _partNumber; } 
    set { _partNumber = value; OnPropertyChanged("PartNumber"); } 
} 

我使用顯式綁定,只有更新源如果檢查出來,否則我只是恢復到原始綁定。

問題是,這是明確使用綁定的最佳方式嗎?如果我得到不同類型的100個元素的BindingExpression,那麼我是否需要每次都手動完成它?我能以更加可重用的方式做到嗎?

+0

你有你的懸而未決的問題的解決方案?也許一個'Explicit'選項用於網格而不是所有控件,併爲所有有界控件調用一次'UpdateSource'。只需「取消」按鈕 – Hamid

回答

1

如果我理解正確,你願意檢查在TextBox中輸入的值,並且只在綁定有效時更新綁定,對嗎?

幸運的是,WPF有一個內置的錯誤處理過程,它比你在那裏做得更乾淨。你應該閱讀一些有關IDataErrorInfo

This article is pretty clear about how to use it

在你的情況的一個例子,你有這樣的事情:

WPF元素:

<TextBox Grid.Row="1" 
     Text="{Binding PartNumber, ValidatesOnDataErrors=True}" 
     Name="ui_partNumber" 
     FontSize="35" 
     VerticalContentAlignment="Center" /> 
<Button Grid.Column="1" 
     Grid.Row="1" 
     Content="OK" 
     Click="PartOKClick" 
     FontSize="20" 
     Width="150" /> 

在你ViewModel,你應該有此:

public string this[string columnName] 
     { 
      get 
      { 
       if (string.Equals(columnName, "PartNumber", StringComparison.OrdinalIgnoreCase) || columnName == string.Empty) 
       { 
        // Here, IDataErrorInfo is checking the property "PartNumber" bound to your TextBox 
        if (this.IsPartNumberValid(ui_partNumber.Text)) 
        { 
         // Not valid: return any error message (string.Empty = no error, otherwise it will be seen as not valid) 
         return "Not valid!"; 
        } 
       } 
       return string.Empty; 
      } 
     } 

這應該爲你做訣竅:如果字符串「無效!」返回時,TextBox將顯示一個紅色邊框,並且Binding將不會更新

+0

我以前曾使用IDataErrorInfo,但它不適合我的應用程序。我的例子很簡單,但有時我需要在我的代碼中做更多的工作,除了做一些動畫(我知道在這種情況下我可以使用數據觸發器)。我選擇了顯式綁定,因爲我需要更多的驗證自由度以及更少的「triggery」開銷,我使用的是更嚴格的MVVM。所以我的問題更多地是關於使用BindingExpression。 +1建議 – Daniel

+0

什麼需要可能會阻止您使用傳統的'IDataErrorInfo' +'Triggers'?既然你提到了最佳實踐,我相信使用它們是這個主要最佳實踐的一部分。也許你的問題可以用這個來克服,如果你可以添加一些代碼/細節 – Damascus

+1

IDataErrorInfo是好的,沒有什麼阻止我在這種情況下使用它。我的問題不是關於數據驗證,而是關於明確更新綁定。另一個簡單的例子是在更新綁定之前添加一個確認UI元素:「你確定你想要嗎?」是=更新源,否=更新目標。 – Daniel

0

爲什麼你不得不使用顯式綁定?爲什麼不在你的ViewModel中進行驗證,然後僅在需要更新時才引發OnPropertyChanged(「BindingParameter」)?

像這樣的東西(在VB):

Property prop as Object 
    Get 
    return _prop 
    End Get 
    Set(ByVal value As Object) 
    If your_validation_check(value) then 
     _prop = value 
     OnPropertyChanged("prop") 'INotifyPropertyChanged 
    End If 
    End Set 
End Property 
+0

因爲我不希望ViewModel在視圖準備發送之前使用更新。 – Daniel

+0

您可以使用MVVM基礎中的弱消息系統,並在視圖模型中有一個偵聽器,該偵聽器觸發OnPropertyChanged事件。 –

+0

我正在使用MVVM。我會修改我的問題,這很清楚。 – Daniel