真正的MVVM和第三方控件

时间:2011-06-29 04:27:08

标签: c# wpf mvvm infragistics xamdatagrid

在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 中的视图实例的情况。

6 个答案:

答案 0 :(得分:10)

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

关于代码隐藏的没有什么本质上不好。事实上,它与您支持视图的所有其他代码没什么不同,例如转换器,自定义控件等。您的视图模型单元测试都不能测试这些代码。代码隐藏的唯一区别是它不太可重用。但它仍然是您的观点的一部分,而观点不错

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

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

如果你仍然死了任何代码隐藏,你可以使用行为,例如ACBBlend Behaviors来编写你原本会放入的功能代码隐藏。只要意识到,甚至行为仍然是视图的一部分,只有更多可重用的代码隐藏。

答案 1 :(得分:3)

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

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

-------编辑---------

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

例如

public class ExportableXamDataGrid: XamDataGrid
{
    public ExportableXamDataGrid():base()
    {
        Messenger.Default.Register<string>(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

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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

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

<i:Interaction.Triggers>
                                <i:EventTrigger EventName="SelectedCellsChanged">
                                    <is:CallDataMethod Method="YourMethodNameInViewModel" />
                                </i:EventTrigger>
</i:Interaction.Triggers>

在View Model中你的方法,即

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

答案 4 :(得分:0)

不要太担心它。是的,拥有“沉重”的观点与MVVM(瘦视图,可测试性)的思想相对立。但规则总是有例外。

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

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

答案 5 :(得分:0)

不是将Excel Exporter保留在 ViewModel 中,而是将其放在导致导出的事件周围的Behavior

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

<i:Interaction.Behaviors>
        <behav:ExcelExporterBehavior MyDataPresenter="{Binding ElementName=myxamdatagrid,Mode=OneTime}"></behav:ExcelExporterBehavior>
</i:Interaction.Behaviors>

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