5

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

就我而言,我使用的是 Infragistics xamDatagrid 控件,并且我想将其数据导出到 Excel。我可以将数据导出到数据网格的 excel 的唯一方法是使用以下代码:

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

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

4

6 回答 6

9

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

代码隐藏本身并没有什么坏处。事实上,它与您为支持您的视图而编写的所有其他代码(如转换器、自定义控件等)并没有太大区别。这些代码都不能通过您的视图模型单元测试进行测试。与代码隐藏的唯一区别是它的可重用性较低。但这仍然是您观点的一部分,观点还不错

一般来说,没有代码隐藏是视图和视图模型之间清晰分离的一个很好的指标。然而,在其他干净的设计中存在一些代码隐藏通常仅表明标准控件、数据绑定和命令难以实现。

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

如果您仍然任何代码隐藏不满意,您可以使用行为,例如ACB混合行为来编写您本来可以放入代码隐藏的功能。只要意识到即使行为仍然是视图的一部分,只是代码隐藏更可重用。

于 2011-06-29T05:09:59.810 回答
3

您可以围绕 xamDataGrid 编写一个包装器,该包装器具有称为文件名的依赖项属性。然后视图模型可以绑定到这个属性。当 xamDataGrid 检测到文件名属性发生更改时,它可以执行您建议的代码。之后重置文件名属性以获得进一步通知。

此解决方案将代码与您的代码隔离开来,并使 xamDataGrid 负责导出其数据。

- - - -编辑 - - - - -

第二种解决方案可以利用 MVVM 轻信使类。不要声明依赖属性,而是让你的包装器监听一条消息。当视图模型发送消息(例如,可以将文件名作为参数)时,包装器可以执行代码。

例如

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");

    }
}

然后在您的视图模型中,您可以执行以下操作:

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

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

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

于 2011-06-29T05:12:01.687 回答
2

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

是的,这会破坏 MVVM,但是使用这些控件它已经被破坏了。通过将解决方案保留在后面的代码中,您将使 ViewModel 尽可能干净,因此当控件确实支持 MVVM 时,更容易清理。

于 2011-06-29T04:43:14.637 回答
1

我强烈建议在 XAML 中使用 System.Windows.Interactivity.Interaction.Triggers 并使用事件触发器来调用 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>

在视图模型中,您的方法即

public void YourMethodNameInViewModel(Object sender, EventArgs e)
    {}
于 2011-06-29T05:21:21.407 回答
0

不要太担心它。是的,拥有“重”视图与 MVVM 的思想(精简视图、可测试性)相反。但规则总有例外。

这里的决定是使用“免费/现有”XAMDataGrid 导出功能或编写您自己的 MVVM 版本(位于 ViewModel 中)。

如果您选择 Option1,您需要在 ViewModel 中缓存 View 对象(使用 ctor 注入)以及设置 View.DataContext = ViewModel 的常用方法并依靠数据绑定来处理其余部分。

于 2011-06-29T05:32:14.083 回答
0

除了将 Excel 导出器保留在ViewModel中之外,您还可以将其放置在触发导出的事件周围的行为中。

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

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

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

于 2016-01-21T19:21:21.897 回答