真正的MVVM和第三方控件

在True MVVM模型中,我们不希望xaml.cs中有任何代码,我们也不希望viewModel具有视图引用。 但是,所有第三方控件都不能为True MVVM提供良好的支持。

在我的情况下,我使用Infragistics xamDatagrid控件,我想将其数据导出到Excel。 我可以将数据导出到数据网格的唯一方法是使用以下代码:

xamDataGridExcelExporter.xamDataGridExcelExporter xamDataGridExcelExporter1 = new xamDataGridExcelExporter.xamDataGridExcelExporter(); xamDataGridExcelExporter1.Export(**this.xamDataGrid1**, @"C:\Excel\ExportFile.xls"); 

但是,XamDataGridExcelExporter将输入作为this.xamDataGrid。 xamDataGrid是View not viewModel的一部分。 那么我们如何处理我们需要viewModel中的视图实例的情况

您可以在xamDataGrid周围编写一个包装器,它具有一个名为filename的dependencyproperty。 然后,viewmodel可以绑定到此属性。 当xamDataGrid检测到filename属性的更改时,它可以执行您建议的代码。 然后重置filename属性以进一步通知。

此解决方案将代码隐藏起来,并使xamDataGrid负责导出其数据。

– – – -编辑 – – – – –

第二种解决方案可以使用MVVM光信使类。 而不是声明依赖属性,让您的包装器听取消息。 当viewmodel发送消息(例如可以将文件名作为参数)时,包装器可以执行代码。

例如

 public class ExportableXamDataGrid: XamDataGrid { public ExportableXamDataGrid():base() { Messenger.Default.Register(this,"ExportExcel",ExportFile); } private void ExportFile(string file) { xamDataGridExcelExporter.xamDataGridExcelExporter xamDataGridExcelExporter1 = new xamDataGridExcelExporter.xamDataGridExcelExporter(); xamDataGridExcelExporter1.Export(**this.xamDataGrid1**, @"C:\Excel\ExportFile.xls"); } } 

然后在您的viewmodel中,您可以执行以下操作:

  Messenger.Default.Send(@"C:\Excel\ExportFile.xls","ExportExcel"); 

您的问题有很多解决方案,所有这些都不必在视图中开始编写逻辑。

http://www.lucbos.net/2011/06/using-codebehind-in-mvvm.html

MVVM禁止代码隐藏是一种常见的误解。 事实上,代码隐藏不可重用,并且与视图密不可分,因此如果没有自动化,它就无法进行unit testing。 但它确实有它的用途。

代码隐藏没有任何本质上的坏处 。 实际上,它您编写的支持视图的所有其他代码(如转换器,自定义控件等)没有太大区别。这些代码都不能通过视图模型unit testing进行测试。 代码隐藏的唯一区别是它不太可重用。 但它仍然是你观点一部分,观点也不错

通常, 缺少代码隐藏是视图与视图模型之间清晰分离的良好指标。 然而,在其他干净的设计中存在一些代码隐藏通常仅表示对标准控件和数据绑定和命令很难做的事情。

在您的情况下,导出XamDataGrid 绝对是视图特定的 。 它必须与您为视图选择的第三方库完全相同。 因此,它完全不应该成为视图模型的一部分。

如果你仍然没有设置任何代码隐藏,你可以使用行为,如ACB或混合行为来编写你将放入代码隐藏的function。 只是意识到即使行为仍然是视图的一部分 ,只有更多可重用的代码隐藏。

我会使用代码,因为“问题”是由视图引起的,所以我会把它保留在那里。

是的,这将打破MVVM,但使用这些控件已经打破了。 通过将代码保留在代码中,您将尽可能保持ViewModel的清洁,因此当控件支持MVVM时,它更容易清理。

我强烈建议在XAML中使用System.Windows.Interactivity.Interaction.Triggers,并使用Event触发器调用XamDataGrid事件并使用’CallDataMethod’,它将调用您将在ViewModel上创建的自定义方法。 最好的事情是你将对象(XamDataGrid)引用作为发送者。

这将是纯粹的MVVM,你将能够实现你的目标。 另外,我建议使用与XamDataGrid相比重量非常轻的WPF DataGrid。 如果您正在使用此控件提供的一些主要function,则仅使用XamDataGrid,因为只是初始化此UI元素,处理器需要200毫秒或更多。

      

并在视图模型中你的方法即

 public void YourMethodNameInViewModel(Object sender, EventArgs e) {} 

不要太在意它。 是的,拥有“沉重”的观点与MVVM(精简观点,可测试性)的观点相对立。 但是规则总是有例外。

这里的决定是使用“自由/现有”XAMDataGrid导出function,或者编写自己的MVVM版本(驻留在ViewModel中)。

如果选择Option1,则需要在ViewModel中缓存View对象(使用ctor注入),另外还需要设置View.DataContext = ViewModel并依靠数据绑定来处理其余部分。

您可以将其放置在触发导出的事件周围的行为中 ,而不是将Excel导出器保留在ViewModel中

在您的行为中创建一个DataPresenter(xamdatagrid)类型依赖项属性,并将其绑定到XAMLcode中的现有xamdatagrid以访问您的xamdatagrid。 这样你就可以在function上实现,而ViewModel将没有UI对象。

    

如果MyDataPresenterExcelExporterBehavior行为中的属性, 行为设置为任何其他UI控件(例如任何要导出的按钮)。