2014-10-09 138 views
1

我想清除一些有關MVVM違規的問題。因爲我已經創建了一些解決方案,用一些項目來演示這些案例。 下面是該解決方案的定義(項目):MVVM違規

  1. 視圖(它的一個WPF類Libraray,顯然它的意見)
  2. 視圖模型(它的一類Libraray,顯然它具有的ViewModels)
  3. 模型(它的一類Libraray,顯然它的型號)
  4. 域(它的一類Libraray它具有應用dataModels)
  5. 核心(其A類Libraray,它有WPF像RelayCommnd或EventToCommand核心)
  6. 應用程序(它的一個WPF應用程序和啓動項目)
  7. ExternalCustomControl(它的一個WPF以假想的第三方公司創建的自定義控制庫)

我給你從下載的整體解決方案,以更好地理解 Here

第一期: 我的EventToCommand MainWindow.xaml關閉活動窗口和連接它MainWindowClosingCommandPassEventArgsToCommand設置爲true,那麼,在MainViewModel有一個名爲OnMainWindowClosing

private void OnMainWindowClosing(object parameter) 
{ 
    var arg = parameter as CancelEventArgs; 

    // What is the best way to show message dialog to user? 
    // Do i have to send message to the View to show the messageBox dialog and then the window send me the answer back to continue? 
    // What about IMessageBoxService? Doesn't it violates MVVM? 

    // Doesn't following code violates the MVVM? 
    // Cancel the Closing of a Window isnt a UI side duty? 
    arg.Cancel = true; 

} 

,完全每當命令處理程序你想設置e.Handlede.Cancel你面臨這個問題。所以你知道任何其他方式,不需要投入參數 as CancelEventArgs

第二期: 我已經在主窗口的EventToCommand。XAMLPreviewMouseDown事件的電網和連接它MouseClickCommandPassEventArgsToCommand設置爲true,那麼,在MainViewModel有名爲命令處理程序OnMouseClick

private void OnMouseClick(object parameter) 
{ 
    //  var arg = parameter as MouseButtonEventArgs; 

    // This is the violation of MVVM : To cast the parameter to MouseButtonEventArgs i have to add a refrence 
    //         to PresentationCore.dll in the ViewModel Project 

    // The next and worse step is that in most cases we need to know the Original Source of the event 
    // (maybe its a StackPanel or a Label or etc) and this again vioaltes the MVVM 

    // So Whats the WorkAround? 

} 

第三期: 我使用了ThirdParty控件(Imagine Infragistics或DevExpress或任何其他第三方控件,但這裏作爲一個例子,我創建了虛構的c ONTROL在我主窗口我作爲ExternalCustomControl項目解決方案),就像這樣:

<thirdParty:ThirdPartyCustomControl Grid.Row="1" 
            ItemsSource="{Binding MyItemsSource,Converter={StaticResource converterKey}}" /> 

ThirdPartyCustomControl具有IEnumarabe<CustomControlDataModel>類型的屬性(CustomControlDataModel是存在於ExternalCustomControl組裝型),但你也知道如果你想創建一個屬性MainViewModel控制與類型CustomControlDataModel你必須添加一個參考ExternalCustomControl.dllViewModel項目和這違反了MVVM,所以我創建了一個ty PE命名MyDataModel和約束所述控制的的ItemsSource到MyItemsSource場所在MainViewModel

// If i define MyItemsSource as List<CustomControlDataModel> i have to add a refrence to ExternalCustomControl.dll 
// and i think its again violate the MVVM (because ExternalCustomControl.dll is a UI Side Controls Assembly) 
public List<MyDataModel> MyItemsSource { get; set; } 

所以我結合類型CustomControlDataModel的屬性類型的屬性MyDataModel當然我需要一個轉換器:

public object Convert(object value, Type targetType, object parameter, c  System.Globalization.CultureInfo culture) 
{ 
    // Imagine when the source data (MyDataModel) is huge (for example 1 milion) it (this dummy Conversion) 
    // affects the performance 

    if (value is List<MyDataModel>) 
    { 
    var result = new List<CustomControlDataModel>(); 

    (value as List<MyDataModel>).ForEach(myVal => 
     { 
     var custDataModel = new CustomControlDataModel(); 
     custDataModel.ID = myVal.ID; 
     custDataModel.Name = myVal.Name; 
     custDataModel.Age = myVal.Age; 

     result.Add(custDataModel); 
     }); 

    return result; 
    } 
    return value; 
} 

和問題是你知道任何更好的w比這個虛擬轉換,或者你通常將你的第三方組件添加到你的視圖和viewmodel?

這些都是我遇到的問題,如果您知道其他問題並將您的專業知識分享給每個人,我將不勝感激。

UPADTE

對於的MessageBox部分第一個問題,我建議這個鏈接 MesageBox

感謝。

+0

[UserControls不應該有視圖模型。](http:// stackoverflow。com/a/25796096/1228)這是*代碼氣味*。你可以告訴,因爲你在做這件事時遇到問題。您也將UI關注點放到視圖模型中。用戶界面關注點在*代碼隱藏*中。 MVVM!=沒有隱藏代碼。 – Will 2014-10-09 13:09:34

+0

@這個問題不是這種情況 – HaMEd 2014-10-12 20:02:04

回答

0

我關閉代碼看起來是這樣的,我不認爲這違反了MVVM

XAML

<Window> 
<i:Interaction.Triggers> 
    <i:EventTrigger EventName="Closing"> 
     <cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" /> 
    </i:EventTrigger> 
    </i:Interaction.Triggers> 

mainviewmodel.cs

public ICommand ClosingCommand 
    { 
     get 
     { 
      return this._closingCommand ?? (this._closingCommand = new DelegateCommand<CancelEventArgs>((args) => 
       { 
        //i set a property in app.xaml.cs when i shut down the app there with 
        //Application.Current.Shutdown(); 
        if (App.IsShutDown) return; 


       if (this.HasChanges) 
       { 
        var result = _msgService.Show("blup blup", "blup", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); 

        if (result == MessageBoxResult.No) 
        { 
         args.Cancel = true; 
        } 
       } 
       else 
       {      
        var result = MessageBox.Show("Blup blup", "blup", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); 

        if (result == MessageBoxResult.No) 
        { 
         args.Cancel = true; 
        } 
       }      
      })); 
     } 
    } 

第三個問題(第三方控制):我不明白你的問題,如果控制需要一種類型的集合,然後通過您的虛擬機公開這些colelction。

第二個問題:好難說。我用這樣的事情,而我想說的是MVVM等;)

<DataGrid x:Name="myGrd"> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="MouseDoubleClick"> 
     <Commanding:EventToCommand Command="{Binding Path=OpenCommand}" 
            CommandParameter="{Binding ElementName=myGrd, Path=SelectedItem}"/> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 

,並在年底我做MVVM但始終不忘做的事情簡單

+0

你的messagebox.show肯定違反了mvvm,注意這個問題不是關於執行,非常感謝你 – HaMEd 2014-10-12 20:16:51

+0

應該是_msgService :)我只是寫出了我的想法 – blindmeis 2014-10-13 06:10:40

0

對於你的第二個問題,我想你只需要重新考慮你想要達到的目標以及爲什麼。

如果您在網格上連接處理程序,然後根據該網格的特定UI元素被點擊在代碼中做出決定,那麼您可能會做錯事。一個叫OnMouseClickCommand也有點味道,因爲那個命令什麼也沒說。一個命令可能類似於UserSelectedCommandGrapefuitSliceRequestedCommand ......即比一般的「被點擊的東西」更具體。

你想嘗試將那些'某種東西'分解爲邏輯,以便在那時發出一個明確而明確的命令,而不是試圖與MouseClickEventArgs一起工作,並在代碼中決定這意味着什麼 - 你的UI應該決定什麼意味着,並向您的虛擬機發出命令。

因此,您的各個UI元素應該具有命令和綁定,而不是嘗試在佈局UI級別設置命令。如果點擊一個Image這意味着某種特定的情況,如果點擊一行DataGrid這意味着某些特定的東西,並且如果拖動這意味着某種特定的東西。創建你的XAML,以便它觸發這些特定的命令,不要將這個責任推到一個模糊的「我的整個用戶界面被點擊,現在我將使用代碼來找出究竟是什麼樣的思維方式。

+0

Fisrt例子:想象我需要一個DragDrop功能,並基於此我想在viewmodel和finnaly中執行一些操作在數據庫中插入一些東西 – HaMEd 2014-10-12 20:07:54

+0

第二個例子:假設我有一個帶有兩個事件RecordUpdating和RecordUpdated的可編輯DataGrid,因爲用戶在記錄中更改somethimg RecordUpdating將在這個事件的事件處理程序中的整個操作是完全的業務類型操作,所以它在視圖模型中,但是您需要將事件arg傳遞給viewmodel以取消或繼續執行更新操作。非常感謝您 – HaMEd 2014-10-12 20:14:06

+0

第一個示例:拖放絕對是一個UI操作,事實也是如此恩我會處理代碼隱藏。一旦我找到了一個元素(或者確定了什麼移動到了哪裏),然後我會觸發一個事件(來自代碼隱藏),將綁定爲ItemSource的底層集合更改爲具有元素的元素拖累。 – Mashton 2014-10-12 20:42:32

1

優秀的問題!

1)我個人認爲你是正確的,使用服務違反了MVVM。幾周前我寫了一篇關於這個確切主題的非常冗長的文章,標題爲Implementing Dialog Boxes in MVVM。在那篇文章中,我提出了一個解決MVVM對話框整體問題的「純粹」解決方案,但是我花了11頁來解釋我是如何到達該設計的。幸運的是,實際實現非常簡單,與數據模板類似,支持您指定的多項目設計,並且可與第三方庫一起使用。有一個閱讀,我總是欣賞客觀反饋。

2)如果您使用的是MVVM Lite,那麼EventToCommand允許您指定參數轉換器。這裏就是我用它來窗口鼠標移動的消息參數轉換成等價表示在我看來型號的例子:

<i:EventTrigger EventName="MouseMove"> 
    <cmd:EventToCommand Command="{Binding ElementName=_this, Mode=OneWay, Path=MouseMoveCommand}" PassEventArgsToCommand="True" EventArgsConverter="{StaticResource MouseEventArgsConverter}" /> 
</i:EventTrigger> 

3)如果我正確理解你的問題我想補充一個參照這兩個視圖,視圖模型項目,至少這是我的項目結構。儘管我通常將我的視圖和視圖模型放置在同一個項目中, MyProject.UI,一切按類別文件夾排序。我在爲一家大型國際公司工作的合同中看到了這一點,實際上它的工作非常好,因爲您通常會同時編輯一個視圖和相應的視圖模型;在解決方案窗口中並排使用它們確實會使整個開發過程變得更加簡單。顯然,一些純粹主義者並不喜歡它,但個人而言,我並不認爲只要讓他們在同一個項目中打破了MVVM,只要你仍然嚴格遵守那個架構。我從來沒有讓它在單元測試等方面產生任何問題,你只需要創建視圖模型。

+0

將視圖和視圖模型放在同一個項目中絕對不會違反任何MVVM概念。有些人喜歡有一個充滿視圖的項目,而另一個人則爲視圖模型,但是我個人的項目是在模塊級而不是在視圖/視圖模型級構建的。 – Mashton 2014-10-13 19:56:41