Настоящий MVVM и сторонние контроли - PullRequest
5 голосов
/ 29 июня 2011

В модели 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, а не viewModel. Итак, как мы можем обрабатывать такие случаи, когда нам нужен экземпляр view в viewModel .

Ответы [ 6 ]

10 голосов
/ 29 июня 2011

Это распространенное заблуждение, что MVVM запрещает выделение кода.Правда в том, что кодовый код не подлежит повторному использованию и неотделим от представления, поэтому он не может быть проверен модулем без автоматизации.Но у него есть свои применения.

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *На самом деле, он не сильно отличается от всего другого кода вашей записи в поддержку вашего представления, такого как преобразователи, пользовательские элементы управления и т. Д. Ни один из этого кода не может быть протестирован вашими модульными тестами модели представления.Единственная разница с выделенным кодом состоит в том, что он менее пригоден для повторного использованияНо это все же часть вашего взгляда , а просмотры неплохо .

В целом, отсутствие 1011 кода позади является хорошим индикаторомчистого разделения между представлением и моделью представления.Однако наличие некоторого кода в другом, как обычно, чистом проекте обычно просто указывает на то, что трудно сделать со стандартными элементами управления, привязкой данных и командами.

В вашем случае экспортXamDataGrid определенно зависит от вида .Это связано именно со сторонней библиотекой, которую вы выбрали для просмотра.Таким образом, имеет смысл , что он не должен быть частью модели представления.

Если вы все еще полностью настроены против любого кода, вы можетеиспользуйте поведения, такие как ACB или Blend Behaviors , чтобы написать функциональность, которую вы в противном случае добавили бы в код.Просто поймите, что даже поведение по-прежнему является частью представления , только более пригодного для повторного использования, чем выделенный код.

3 голосов
/ 29 июня 2011

Вы можете написать обертку вокруг xamDataGrid, у которой есть свойство зависимости, называемое имя файла. Затем модель представления может связываться с этим свойством. Когда xamDataGrid обнаруживает изменение свойства имени файла, он может выполнить предложенный вами код. После этого сбросьте свойство имени файла для дальнейшего уведомления.

Это решение скрывает код от вашего кода и делает xamDataGrid ответственным за экспорт своих данных.

------- редактировать ---------

Второе решение может использовать класс легких посланников MVVM. Вместо объявления свойства зависимости заставьте свою оболочку прослушивать сообщение. Когда 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 голосов
/ 29 июня 2011

Я бы использовал код позади, потому что «проблема» вызвана представлением, поэтому я бы оставил его там.

Да, это сломает MVVM, но при использовании этих элементов управления оно уже сломано. Сохраняя решение в своем коде, вы будете поддерживать ViewModel настолько чистым, насколько это возможно, поэтому, когда элементы управления поддерживают MVVM, его легче очистить.

0 голосов
/ 21 января 2016

Вместо сохранения Excel Exporter в ViewModel вы можете поместить его в Поведение вокруг события, при котором вы запускаете экспорт.

создайте в вашем поведении свойство зависимости типа DataPresenter (xamdatagrid) и свяжите его с существующим xamdatagrid в XAMLcode, чтобы получить доступ к вашему xamdatagrid. Таким образом, вы достигнете функциональной цели, и ViewModel будет свободен от объектов пользовательского интерфейса.

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

if MyDataPresenter - это свойство в поведении ExcelExporterBehavior , которое устанавливается для любого другого элемента управления пользовательского интерфейса (скажем, любой кнопки для экспорта).

0 голосов
/ 29 июня 2011

Не беспокойся об этом.Да, «тяжелые» представления противоречат идеям MVVM (тонкие представления, тестируемость).Но из этого правила всегда есть исключения.

Решение здесь заключается в использовании «свободной / существующей» функции экспорта XAMDataGrid или написании своей собственной версии MVVM (которая находится во ViewModel).

Если вы выберете Option1, вам нужно будет кэшировать объект View в ViewModel (использовать инъекцию ctor) в дополнение к обычному подходу установки View.DataContext = ViewModel и использования привязки данных для обработки остальных,

0 голосов
/ 29 июня 2011

Я настоятельно рекомендую использовать System.Windows.Interactivity.Interaction.Triggers в XAML и использовать триггер Event для вызова события XamDataGrid и использовать CallDataMethod, который вызовет пользовательский метод, который вы создадите в ViewModel. , Лучше всего то, что вы получите ссылку на объект (XamDataGrid) в качестве отправителя.

Это будет чисто MVVM, и вы сможете достичь своей цели. Кроме того, я бы рекомендовал использовать WPF DataGrid, который очень легкий по сравнению с XamDataGrid. Используйте XamDataGrid, только если вы используете некоторые основные функциональные возможности, предоставляемые этим элементом управления, потому что только для инициализации этого элемента пользовательского интерфейса процессор занимает 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)
    {}
...