简体   繁体   English

真正的 MVVM 和第三方控制

[英]True MVVM and third party controls

In a True MVVM model we do not expect any code behind in xaml.cs also we do not expect viewModel to have refernece of view.在真正的 MVVM model 中,我们不希望 xaml.cs 中有任何代码,我们也不希望 viewModel 具有视图参考。 However all third party controls do not provide good support for True MVVM.但是,所有第三方控件都不能很好地支持 True MVVM。

In my case I am using Infragistics xamDatagrid control and I want to export its data to excel.就我而言,我使用的是 Infragistics xamDatagrid 控件,我想将其数据导出到 excel。 The only way I can export data to excel of data grid is by using following code:我可以将数据导出到数据网格的 excel 的唯一方法是使用以下代码:

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

However, XamDataGridExcelExporter takes input as this.xamDataGrid.但是,XamDataGridExcelExporter 将输入作为 this.xamDataGrid。 xamDataGrid is part of View not viewModel. xamDataGrid 是 View 而不是 viewModel 的一部分。 So how can we handle such kind of cases where we need instance of view in viewModel .那么我们如何处理这种需要 viewModel 中的视图实例的情况

It is a common misconception that MVVM forbids code-behind. MVVM 禁止代码隐藏是一个常见的误解。 The truth is that code-behind is not reusable and it is inseparable from the view, so it cannot be unit tested without automation.事实是,代码隐藏是不可重用的,它与视图密不可分,因此没有自动化就无法进行单元测试。 But it does have its uses.但它确实有它的用途。

There is nothing inherently bad about code-behind.代码隐藏本身并没有什么坏处 In fact, it's not much different than all the other code your write in support of your view like converters, custom controls, etc. None of this code can be tested by your view-model unit tests.事实上,它与您为支持您的视图而编写的所有其他代码(如转换器、自定义控件等)并没有太大区别。这些代码都不能通过您的视图模型单元测试进行测试。 The only difference with code-behind is that it is less reusable.与代码隐藏的唯一区别是它的可重用性较低。 But it's still part of your view and views are not bad .但这仍然是您观点的一部分,观点还不错

In general, the absence of code-behind is a good indicator of a clean separation between the view and the view-model.一般来说,没有代码隐藏是视图和视图模型之间清晰分离的一个很好的指标。 However the presence of some code-behind in an otherwise clean design usually merely indicates something that is hard to do with the standard controls and data binding and commands.然而,在其他干净的设计中存在一些代码隐藏通常仅表明标准控件和数据绑定和命令难以做到的事情。

In your case, exporting the XamDataGrid is definitely view-specific .在您的情况下,导出XamDataGrid绝对是特定于视图的 It has to do precisely with the third-party library you have chosen for the view.它与您为视图选择的第三方库完全相关。 So it makes perfect sense that it should not be part of the view-model.因此,它不应该成为视图模型的一部分是完全有道理的。

If you are are still dead set against any code-behind, you can use behaviors, such as ACB orBlend Behaviors to write functionality that you would otherwise put into the code-behind.如果您仍然对任何代码隐藏感到死心塌地,您可以使用行为,例如ACB混合行为来编写您本来可以放入代码隐藏中的功能。 Just realize that even behaviors are still part of the view , only more reusable that code-behind.只要意识到即使行为仍然是视图的一部分,只是代码隐藏更可重用。

You can write a wrapper around xamDataGrid that has a dependencyproperty called filename.您可以围绕 xamDataGrid 编写一个包装器,该包装器具有称为文件名的依赖项属性。 The viewmodel can then bind to this property.然后视图模型可以绑定到这个属性。 When the xamDataGrid detects a change on the filename property it can then execute the code you suggested.当 xamDataGrid 检测到文件名属性发生更改时,它可以执行您建议的代码。 Afterwards reset the filename property for further notification.之后重置文件名属性以获得进一步通知。

This solution keeps out the code from you code behind and makes the xamDataGrid responsible for exporting its data.此解决方案将代码与您的代码隔离开来,并使 xamDataGrid 负责导出其数据。

-------edit--------- - - - -编辑 - - - - -

A second solution can make use of the MVVM light messenger class.第二种解决方案可以利用 MVVM 光信使 class。 In stead of declaring a dependency property, make your wrapper listen to a message.不要声明依赖属性,而是让你的包装器监听一条消息。 When the viewmodel sends the message (which could for example have the filename as parameter) the wrapper can then execute the code.当视图模型发送消息(例如,可以将文件名作为参数)时,包装器可以执行代码。

eg例如

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

    }
}

Then in your viewmodel you can do:然后在您的视图模型中,您可以执行以下操作:

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

There are many solutions to your problem, all of which you do not have to start writing logic in your view.您的问题有很多解决方案,所有这些您都不必在视图中开始编写逻辑。

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

I'd use code behind because the 'problem' is cause by the view so I would keep it there.我会使用后面的代码,因为“问题”是由视图引起的,所以我会把它留在那里。

Yes, that will break MVVM but using these controls it is already broken.是的,这会破坏 MVVM,但是使用这些控件它已经被破坏了。 By keeping the solution in the code behind you willl keep the ViewModel as clean as possible so when the controls do support MVVM it is easier to clean up.通过将解决方案保留在后面的代码中,您将使 ViewModel 尽可能干净,因此当控件确实支持 MVVM 时,更容易清理。

Instead of keeping the Excel Exporter in ViewModel you can place it in a Behavior around the event you are triggering the export.与其将 Excel 导出器保留在ViewModel中,不如将其放置在触发导出的事件周围的行为中。

create a DataPresenter(xamdatagrid) type dependency property in your behavior and bind that to your existing xamdatagrid in XAMLcode to get access of your xamdatagrid.在您的行为中创建一个 DataPresenter(xamdatagrid) 类型依赖属性,并将其绑定到 XAMLcode 中的现有 xamdatagrid 以访问您的 xamdatagrid。 This way you'll functionally achieve and ViewModel will be free of UI objects.这样,您将在功能上实现并且 ViewModel 将没有 UI 对象。

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

if MyDataPresenter is the property in ExcelExporterBehavior behavior which is set to any other UI control (say any button to export).如果MyDataPresenterExcelExporterBehavior行为中的属性,该属性设置为任何其他 UI 控件(例如要导出的任何按钮)。

I'd strongly recommend to use System.Windows.Interactivity.Interaction.Triggers in XAML and use the Event trigger to call a event of XamDataGrid and use 'CallDataMethod' which will call a custom method that you will create on the ViewModel.我强烈建议在 XAML 中使用 System.Windows.Interactivity.Interaction.Triggers 并使用事件触发器来调用 XamDataGrid 的事件并使用“CallDataMethod”,这将调用您将在 ViewModel 上创建的自定义方法。 The best thing in this is that you will get the object(XamDataGrid) reference as sender.最好的事情是您将对象(XamDataGrid)引用作为发件人。

This will be purely MVVM and you will be able to acheive your goal.这将是纯粹的 MVVM,您将能够实现您的目标。 Also, i would recommend to use WPF DataGrid which is very light weight as compared to XamDataGrid.另外,我建议使用 WPF DataGrid,与 XamDataGrid 相比,它的重量非常轻。 Only use XamDataGrid if you are using some major functionalities provided by this control, cuz just to initialize this UI Element the processor takes 200 milliseconds or may be more.仅当您使用此控件提供的某些主要功能时才使用 XamDataGrid,因为仅初始化此 UI 元素处理器需要 200 毫秒或更多时间。

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

And in the View Model your Method ie并在查看 Model 您的方法即

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

Don't worry too much about it.不要太担心它。 Yes, having "heavy" views is opposed to the ideas of MVVM (thin views, testability).是的,拥有“重”视图与 MVVM 的思想(精简视图、可测试性)相反。 But there are always exceptions to the rule.但规则总有例外。

The decision here is using the "free/existing" XAMDataGrid export functionality or write your own MVVM version of it (which resides in the ViewModel).这里的决定是使用“免费/现有”XAMDataGrid 导出功能或编写您自己的 MVVM 版本(位于 ViewModel 中)。

If you choose Option1, you'd need to cache the View object within the ViewModel (use ctor injection) in addition the usual approach of setting View.DataContext = ViewModel and relying on data-binding to handle the rest.如果您选择 Option1,则需要在 ViewModel 中缓存 View object(使用 ctor 注入),此外还需要设置 View.DataContext = ViewModel 并依靠数据绑定来处理 rest 的常用方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM