2015-12-09 4 views
1

ViewModel1 динамически импортирует источник данных из модели путем импорта CSV-файла, содержащего значения данных и их расстояния. ViewModel1 имеет два параметризованных конструктора. Он создает серию рассеяния и сохраняет ее в коллекции серии.Как связать общее свойство двух ViewModels динамически? (MVVM, ViewModel-First)

private IEnumerable<Series> _myScatterSeries = new Collection<Series>(); 

View1 создан в ответ на ViewModel1 с использованием DataTemplates. View1 связывается с свойством MyScatterSeries ViewModel1 и показывает представление серии в диаграмме рассеяния.
View1.xaml:

<Grid Loaded="Grid_Loaded"> 
    <ext:ChartExtension Style="{StaticResource ChartStyle1}" SeriesSource="{Binding MyScatterSeries}" /> 
</Grid> 

Я хочу, чтобы создать новый вид окна (VIEW2) и он должен загрузить один и тот же разброс серии, созданный ViewModel1 dynacamically, когда я открываю окно VIEW2. Я попытался использовать тот же код выше в View2, но он отображает только диаграмму, но теперь данные о точках данных. Как я могу связать свойство MyScatterSeries для ViewModel1 с View2 динамически?

Я не могу использовать следующее, поскольку он имеет проблемы с аргументами конструктора. View2.xaml-

<UserControl.DataContext> 
    <vm:ViewModel1/> 
</UserControl.DataContext> 

Я также попытался с помощью DataTemplate, добавив стека панель и обертывание два Вида, но он не работает.

Поскольку это подход ViewModel-First, я создал новый ViewModel (ViewModel2) для View2. Но я не знаю, как связать MyScatterSeries ViewModel1 с ViewModel2, используя код. Кроме того, могу ли я использовать тот же код View1, чтобы показать серию рассеяния в View2?

ответ

2

Моя первая мысль - иметь один ApplicationViewModel, который содержит как ViewModel1, так и ViewModel2, и берет на себя управление синхронизацией данных.

Вот очень грубый пример, который должен дать вам общее представление о том

public class ApplicationViewModel 
{ 
    ViewModel1 ViewModel1 { get; set; } 
    ViewModel2 ViewModel2 { get; set; } 

    public ApplicationViewModel() 
    { 
     ViewModel1 = new ViewModel1(someParameters); 
     ViewModel2 = new ViewModel2(otherParameters); 

     ViewModel1.PropertyChanged += VM1_PropertyChanged; 
    } 

    private VM1_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == "ScatterSeries") 
      ViewModel2.ScatterSeries = ViewModel1.ScatterSeries; 
    }  
} 

Вы также можете использовать этот же метод, чтобы оба объекта указывают на тот же объект, если вы не хотите (не знаю, как обновляется эти данные или поддерживается пользователем)

public class ApplicationViewModel 
{ 
    ViewModel1 ViewModel1 { get; set; } 
    ViewModel2 ViewModel2 { get; set; } 

    private IEnumerable<Series> _myScatterSeries; 

    public ApplicationViewModel() 
    { 
     _myScatterSeries = new Collection<Series>(); 

     ViewModel1 = new ViewModel1(someParameters, _myScatterSeries); 
     ViewModel2 = new ViewModel2(otherParameters, _myScatterSeries); 
    } 
} 

Другим вариантом было бы использовать какую-то систему обмена сообщениями для передачи сообщения при изменении данных VM1 и VM2 бы подписаться на эти сообщения и взять под контроль синхронизации данных. Это большой вопрос, но я кратко просмотрю свой блог на Communication between ViewModels with MVVM, если вы заинтересованы.

И, наконец, вы можете просто убедиться, что у View1 и View2 есть свой DataContext, установленный в ViewModel1, предполагая, что там нет других различий. Например,

<DataTemplate x:Key="View1"> 
    <vw:View1/> 
</DataTemplate> 
<DataTemplate x:Key="View2"> 
    <vw:View2 /> 
</DataTemplate> 

... 

<ContentControl Content="{Binding ViewModel1}" ContentTemplate="{StaticResource View1}" /> 
<ContentControl Content="{Binding ViewModel1}" ContentTemplate="{StaticResource View2}" /> 

Я не вижу, как ваш .DataContext установлен в вашем коде выше, поэтому не может предоставить соответствующий образец кода для этого, но это всегда выбор.

+0

Представления присваиваются соответствующим ViewModels с использованием DataTemplate в Файл MainWindow.Resources.xaml. ' ' View1 в ответ на изменения свойств ViewModel1 и View2 для ViewModel2. Я должен реализовать новый алгоритм в ViewModel2, на серии Scatter, сгенерированный ViewModel1. И я не хочу писать тот же код ViewModel1 для генерации сечений рассеяния в ViewModel2. – Prasad

+0

Если оба 'View1' и' View2' могут использовать тот же самый ViewModel, вы можете использовать шаблон Named вместо неявного шаблона. Я обновляю свой ответ, чтобы показать пример этого, однако ваш конкретный XAML, вероятно, будет зависеть от того, как ViewModel1 добавляется в дерево пользовательского интерфейса (TabControl, ItemsControl, ContentControl и т. Д.) – Rachel

+0

. Я исследовал еще и обнаружил, что первые ViewModels должны быть когда мы запускаем Application.Views добавлены в tabcontrol. MyScatterSeries получает представление серии, рассчитанное из CSV-файла в ViewModel1, а View1 отображает его, привязывая SeriesSource к MyScatterSeries. Итак, есть ли способ: 1) иметь MyScatterSeries как общее свойство между ViewModel 1 и ViewModel2, 2), и обновление свойства MyScatterSeries в ViewModel1 также будет динамически обновляться в ViewModel2. [1/2] – Prasad

-1

Вы можете программно задать DataContext для просмотра в конструкторе вроде этого:

//Constructor 
public View2() 
{ 
    InitializeComponent(); 
    DataContext = new ExampleViewModel(); 
} 

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

+0

Не в духе MVVM –

+1

@ RyanSearle Да, если ему нужно передать аргументы и не использовать какую-либо фреймворк, и он хочет сохранить его простым без ViewModelLocator и т. Д. – adminSoftDK