2014-10-09 97 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