2016-08-08 3 views
-1

Я просто не могу понять это. Поэтому я постараюсь лучше описать свою проблему.Передача данных через модели просмотра

Я создаю приложение с использованием шаблона MVVM. У меня есть пользовательский контроль AAAView с viewmodel AAAViewModel, который используется для заполнения класса данных CDataClass. У меня также есть главное окно MainView и его viewmodel MainViewModel. Затем у меня есть окно DialogView с DialogViewModel.

Итак, теперь MainViewModel (у которого есть собственный пользовательский элемент управления) создает DialogViewModel (с другим экземпляром пользовательского элемента управления). Как я могу передать данные в CDataClass между этими двумя пользовательскими элементами управления? Я попытался создать свойство в , который будет содержать экземпляр MainViewModel или DialogViewModel, поэтому я могу передавать данные, но я зацикливаюсь, потому что я не мог сделать это как свойство зависимости.

Image representation of problem

Моя цель состоит в том, чтобы сделать пользовательский элемент управления, который может использоваться в различных режимах, которые могут иметь различные данные в нижележащих CDataClass.

Просто для уточнения ... Я использую пользовательский контроль как <views:GeneralInfoView Grid.Row="0" /> и не знаю, как обмениваться данными между двумя разными экземплярами одного и того же пользовательского элемента управления в разных представлениях. Любая точка в какой-то схеме или методе была бы очень оценена.

Благодарим за помощь.

+0

Если данные CDataClass отличаются между этими двумя представлениями, то они в основном являются отдельными экземплярами, не так ли? – Steve

+0

http://stackoverflow.com/q/3801681/2470362 –

ответ

1

Я не думаю, что это идеальный вариант, когда у вас есть архитектура вашего приложения, схематичная как отношения между представлениями; Я думаю, что лучший способ подумать об этом - это набор отношений между режимами просмотра, при этом взгляды висят над этим деревом по мере необходимости. Когда вы думаете об этом так, «как передаются данные» становится намного проще. Вид - это всего лишь канал между моделью просмотра и пользователем. Вы не проектируете дом как набор окон и телефонов, а затем пытаетесь выяснить план этажа. Вы начинаете с того, что делает дом и как люди будут жить в нем.

Так это легко:

Некоторые ViewModels имеют AAViewModel свойство. В этих моделях просмотра могут быть всевозможные простые или сложные взгляды; если представление хочет, чтобы пользователь редактировал файл AAViewModel вида viewmodel, он включает в себя AAView, привязанный соответствующим образом к файлу viewmodel AAViewModel. Ваши MainViewModel и DialogViewModel - это большие сложные интерактивные представления, которые хотят, чтобы кто-то редактировал их vm's AAViewModel.

Если MainViewModel является DialogViewModel «родитель, или создан временный экземпляр DialogViewModel просто поместить в модальный диалог, то MainViewModel покажет диалоговое окно и посмотреть на dialogVM.AAVM.CData.IsDirty, чтобы решить, что делать с ним. Или, возможно, он дает dialogVM.AAVM новый экземпляр CDataClass, прежде чем показывать диалог (возможно, клон его собственного экземпляра), и если ShowModel() возвращает true, то он что-то делает с dialogVM.AAVM.CData.

Дело в том, что после того, как ваши модели будут управлять всем, для них становится относительно простым общение друг с другом. Родитель-ребенок прост: родитель дает материал ребенку и смотрит на то, что ребенок возвращает. Модель просмотра может подписаться на событие PropertyChanged другого вида viewmodel; родительская модель просмотра может контролировать своих детей; когда что-то происходит у ребенка, родитель может решить, следует ли обновлять родного брата.В общем, дети не должны знать ничего о своих родителях; это значительно облегчает повторное использование дочерних моделей просмотра в разрозненных контекстах. Родители должны решить, что делать с этой информацией.

Все AAViewModel знает, что кто-то вручил ему копию CDataClass; он соответственно обновляет свои публичные свойства. Тогда кто-то еще (возможно, AAView, но он не знает) передает ему некоторые изменения, устанавливая его свойства; он соответственно обновляет свой экземпляр CDataClass. Через некоторое время, неизвестное ему, появляется одна модель или другая модель и смотрит на это CDataClass.

И связь между видами и режимами просмотра происходит через привязки.

UPDATE

Оказывается, что вы создаете ViewModels в своих взглядах, и в результате вы не имеете ни малейшего представления о том, как родители могут получить к ним. И теперь вы знаете, почему не так хорошо создавать модели просмотра child view.

Вот как вы вид ребенка/ViewModels в ViewModel-ориентированный дизайн я описал выше:

Во-первых, избавиться от того, что Вы делаете, чтобы создать дочерние ViewModels внутри вида.

Во-вторых, создайте DataTemplate для детского вида модели. Это должно быть в словаре ресурсов, который объединен с ресурсами в App.xaml, но это так просто, что он не убьет вас, если вы ленитесь и просто вставьте его в Resources двух разных видов, где он используется.

Я не знаю, как выглядят ваши объявления пространства имен. Я собираюсь предположить, что взгляды находятся в чем-то под названием xmlns:view="...", а viewmodels - в чем-то под названием xmlns:vm="...".

<DataTemplate DataType="{x:Type vm:AAAViewModel}"> 
    <view:AAAView /> 
</DataTemplate> 

Теперь вы можете назначить AAAViewModel к ContentProperty любого контроля, который наследует от ContentControl (и это большинство из них), и шаблон будет экземпляр. Это означает, что XAML создаст для вас AAAView и назначит этот экземпляр AAAViewModel объекту DataContextAAAView, который он только что создал.

Итак, давайте создадим ребенка AAAViewModel, а затем мы покажем его в пользовательском интерфейсе.

public class DialogViewModel 
{ 

    // You can create this in DialogViewModel's constructor if you need to 
    // give it parameters that won't be known until then. 
    private AAAViewModel _aaavm = new AAAViewModel(); 
    public AAAViewModel AAAVM 
    { 
     get { return _aaavm; } 
     protected set { 
      _aaavm = value; 
      OnPropertyChanged(nameof(AAAVM)); 
     } 
    } 

И теперь мы можем отобразить AAAVM в DialogView:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 

    <ContentControl 
     Content="{Binding AAAVM}" 
     Grid.Row="0" 
     /> 

    <StackPanel Orientation="Vertical" Grid.Row="1"> 
     <!-- Other stuff --> 
    </StackPanel> 
</Grid> 

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

Не совсем то же самое, но близко. Во-первых, еще раз, избавитесь от того, что вы делаете, когда диалог создает свою собственную модель просмотра.

MainViewModel.cs

public CDataClass CDC { /* you know the drill */ } 

public void ShowDialog() 
{ 
    var dvm = new DialogViewModel(); 

    // Maybe this isn't what you want; I don't know what CDataClass does. 
    // But I'm assuming it has a copy constructor. 
    dvm.AAAVM.CDC = new CDataClass(this.CDC); 

    if (DialogView.ShowDialog(dvm).GetValueOrDefault()) 
    { 
     CDC = dvm.CDC; 
    } 
} 

Обратите внимание, что следующий следующий - код вида, не viewmodel.

DialogView.xaml.cs

public static bool? ShowDialog(DialogViewModel dvm) 
{ 
    var vw = new DialogView() { DataContext = dvm }; 

    return vw.ShowDialog(); 
} 

Теперь вы могли позволить диалог продолжать создавать свою собственную ViewModel; в этом случае вы могли бы дать ему общественную собственность, как это:

public DialogViewModel ViewModel => (DialogViewModel)DataContext; 

И метод ShowDialog так:

DialogView.xaml.cs

public static bool? ShowDialog(CDataClass cdc) 
{ 
    var dlg = new DialogView(); 

    dlg.ViewModel.AAAVVM.CDC = cdc; 

    return dlg.ShowDialog(); 
} 

И тогда родитель может взаимодействовать с это нравится вместо этого:

MainViewModel.cs

public void ShowDialog() 
{ 
    var cdcClone = new CDataClass(this.CDC); 

    if (DialogView.ShowDialog(cdcClone).GetValueOrDefault()) 
    { 
     CDC = cdcClone; 
    } 
} 

Nice и аккуратный.

Если это диалоговое окно не является модальным, сделайте диалог viewmodel частным членом MainViewModel и получите MainViewModel подпишитесь на события в диалоговом режиме, чтобы быть в курсе того, что делает диалог. Всякий раз, когда пользователь обновляет копию диалогового окна CDataClass, диалог будет поднимать DataClassUpdated, а MainViewModel будет иметь обработчик для этого события, который обнюхивает _dialogViewModel.AAAVM.CDC и решает, что с ним делать. В случае необходимости мы можем привести пример кода.

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

+0

Хорошо, я понял. Но как я могу получить что-то из AAAViewModel, если у меня нет доступа к нему. AAAViewModel создается автоматически с представлением, а не с кодом. Пользовательский вид управления определен в DialogView в xaml как , поэтому я не вижу, как я могу получить доступ к модели просмотра за ней из DialogViewModel. – benderto

+0

@benderto Вот почему вы не создаете свои модели просмотра именно так! Когда я получаю в офисе через час или два, я покажу вам, как это сделать как DataTemplate. –

+0

@benderto Обновленный ответ. –

Смежные вопросы