2012-11-28 43 views
1

我正在使用DataTemplate將某些代碼轉換爲更合適的MVVM實現,並且在某些類型的UI驗證方面存在問題。MVVM中的UI綁定驗證

我在視圖模型驗證沒有問題 - IDataErrorInfo已實施,一切都很好。我遇到的一個問題是界面綁定錯誤,他們可能會把一個TextBox中的字母綁定到int。

以前,我用:

System.Windows.Controls.Validation.AddErrorHandler(userControl, handler) 

...並保持添加和刪除錯誤的計數知道所有形式的數據是否OK。

但現在我正在做MVVM,我沒有訪問userControl來設置這個處理程序。所以我真的沒有一個鉤子來開始。

是否有某種形式的全球DataTemplateApplied事件處理程序的提供,我可以這樣做:

void OnDataTemplateApplied(object data, Control template) 
{ 
    if (data is MyViewModelBase) 
    { 
    Validation.AddErrorHandler(template, handler); 
    } 
} 

或者,也許我可以在引導程序的外殼窗口調用AddErrorHandler一次,然後每次事件被炒魷魚找出哪個ViewModel爲這個特定的控件提供動力?

我知道有些人喜歡製作所有虛擬機字段字符串,並在虛擬機中進行大量類型轉換 - 由於各種原因,這對我們的系統並不現實。

回答

2

您或許對這個問題有很大的興趣:https://stackoverflow.com/a/13335971/1094526 主要思想就是你說的(訂閱錯誤處理程序)。據我所知,問題是你沒有訪問從ViewModel的控制,但它不難解決在我工作的項目中,我暴露了我的ViewModel的兩個方法:AddUIError和RemoveUIError。我在View中創建了一個事件處理程序,然後將DataContext轉換爲ViewModel的類型,並根據發生的情況調用AddUIError或RemoveUIError。 我正在使用DataTemplates將視圖與ViewModel相關聯,所以當應用模板時,DataContext會自動設置爲ViewModel。如果你願意,你可以存儲在私有字段(視圖)您的視圖模型,每次DataContext的變化更新參考(有一個DataContextChanged僅事件)

如果將多個的ViewModels來完成,你可以把這兩個方法(AddUIError和RemoveUIError)在類ViewModelBase中移動,並將ValidationError事件處理移動到行爲並在每個視圖中使用它。


有關行爲的一部分更多信息: 的行爲類是Expression Blend的SDK的一部分,所以你需要它,如果你想跟隨這樣。例如,行爲可用於將許多組件的一些常用功能附加到許多組件上,而不會創建派生類。

首先,我們需要定義AddUIError和RemoveUIError在一個名爲ViewModelBase類(這是當然的,對於所有其他的ViewModels的基類):

class ViewModelBase { 
    public void AddUIError(...) {/* Details ommitted */ } 
    public void RemoveUIError(...) {/* Details ommitted */ } 
} 

然後,通過繼承行爲創建行爲。我們使用FrameworkElement的作爲模板參數,因此這種行爲可以連接到任何FrameworkElement的(或派生類)實例:

class NotifyDataErrorsBehavior : Behavior<FrameworkElement> 
{ 
    // Called when the the Behavior is attached 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     // Initialize the handler for the Validation Error Event 
     _handler = new RoutedEventHandler(OnValidationRaised); 
     // Add the handler to the event from the element which is attaching this behavior 
     AssociatedObject.AddHandler(System.Windows.Controls.Validation.ErrorEvent, _handler); 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     // Remove the event handler from the associated object 
     AssociatedObject.RemoveHandler(System.Windows.Controls.Validation.ErrorEvent, _handler); 
    } 

    private RoutedEventHandler _handler = null; 


    private void OnValidationRaised(object sender, RoutedEventArgs e) 
    { 
     var args = (System.Windows.Controls.ValidationErrorEventArgs)e; 

     ViewModelBase viewModel = AssociatedObject.DataContext as ViewModelBase; 
     if (viewModel != null) 
     { 
      // You can add only Exception validation errors if you want.. 

      if (args.Action == ValidationErrorEventAction.Added) 
       viewModel.AddUIValidationError(...); 
      else if (args.Action == ValidationErrorEventAction.Removed) 
       viewModel.RemoveUIValidationError(...); 
      else 
       throw new NotSupportedException("ValidationErrorEventAction has changed"); 
     } 
    } 
} 

最後只是用它在XAML: 1.添加引用命名空間,其中NotifyDataErrorsBehavior是位置,並且還System.Windows.Interactivity命名空間的引用(從Expression Blend的SDK):

<UserControl 
     ... 
     xmlns:behavior="clr-namespace:MyApp.Behaviors" 
     xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
     ... 
> 

2.添加行爲(在相同的水平,你的用戶控件的內容:

<i:Interaction.Behaviors> 
    <behavior:NotifyDataErrorsBehavior/> 
</i:Interaction.Behaviors> 

例:

<UserControl 
     ... 
     xmlns:behavior="clr-namespace:MyApp.Behaviors" 
     xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
     ... 
> 
    <i:Interaction.Behaviors> 
     <behavior:NotifyDataErrorsBehavior/> 
    </i:Interaction.Behaviors> 
    <Grid> 
     ... 
    </Grid> 
</UserControl> 
+0

你能給關於「移動ValidationError事件處理的行爲」多一點點信息?現在我的知識中,行爲有點像黑洞,但聽起來這就是我想要的。我有幾十個視圖,並且正在尋找全局代碼,而不是將樣板文件複製並粘貼到我創建的每個視圖。 Visual Studio Designer使得將每個視圖UserControls的繼承改爲一個通用基類有些痛苦,但那是我的備份計劃。 – Clyde

+0

編輯帖子以添加行爲示例。 是的,我出於同樣的原因使用了行爲。我不想將所有的xaml文件都更改爲新類,並且發現這些行爲非常易於使用,並且對於這種情況似乎很有效 –

+0

太棒了,謝謝。 – Clyde