2015-08-03 3 views
1

Следуя this tutorial (среди других) и чтения на вопросы здесь я построил навигационный механизм, который позволит мне передать параметры между моим ViewModels:
баз Object - каждый вид модель наследует от него:WPF MVVM навигация с параметрами

public abstract class ObjectBase : INotifyPropertyChanged 
{ 
    //INotifyPropertyChanged members 
    ... 

    //Navigation handling 
    public abstract ObjectBase BackLocation { get; } 

    public abstract event Action<ObjectBase> NavigateTo; 

    public abstract string ViewHeader { get; } 
} 

MainViewModel - отвечает за навигацию:

public class MainViewModel : ObjectBase 
{ 
    private ObjectBase _selectedView; 
    private CommandBase _backCommand; 

    public MainViewModel() 
    { 
     SelectedView = new FirstViewModel(); 
    } 

    public ObjectBase SelectedView 
    { 
     get { return _selectedView; } 
     set 
     { 
      SetProperty(ref _selectedView, value); 
      //register to the navigation event of the new view 
      SelectedView.NavigateTo += (target)=> { SelectedView = target; }; 
     } 
    } 

    //This command is bound to a Back button on the main view 
    public CommandBase BackCommand 
    { 
     get { return _backCommand ?? (_backCommand = new CommandBase(Back)); } 
    } 

    private void Back(object obj) 
    { 
     if (SelectedView.BackLocation != null) 
     { 
      SelectedView = SelectedView.BackLocation; 
     } 
     else 
     { 
      Application.Current.Shutdown(); 
     } 
    } 
} 

И главный вид:

<Window ...  
<Window.DataContext> 
    <vm:MainViewModel/> 
</Window.DataContext> 
<Window.Resources> 
    <DataTemplate DataType="{x:Type vm:FirstViewModel}"> 
     <views:FirstView/> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type vm:SecondViewModel}"> 
     <views:SecondView/> 
    </DataTemplate> 
</Window.Resources> 
<ContentPresenter Content="{Binding SelectedView}"/> 
</Window> 

Моя проблема: Если я устанавливаю DataTemplates в главном окне, как выше, что делает каждый из просмотра осознает это DataContext, так что если я хочу, чтобы добавить DataContext явно вид для того, чтобы использовать IntelliSense, как это:

<UserControl x:Class="Wpf_NavigationTest.Views.FirstView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:viewModels="clr-namespace:Wpf_NavigationTest.ViewModels"> 
<!--this causes the view model's constructor to get called again--> 
<UserControl.DataContext> 
    <viewModels:FirstViewModel/> 
</UserControl.DataContext> 
<Grid> 
    <TextBlock Text="User control 1" FontSize="40"/>  
</Grid> 

View Model's конструктор вызывается дважды, теряя пункт метров, прошедших мимо события Navigate.

+0

«* так что, если я хочу явно добавить« DataContext »в представление *» - Можете ли вы привести пример того, как вы это достигаете? –

+0

@MikeEason добавлено – Yoav

ответ

0

Проблема заключается в том, что вы устанавливаете DataContext внутри своего UserControl, а также в вашей основной модели.

<UserControl.DataContext> 
    <viewModels:FirstViewModel/> 
</UserControl.DataContext> 

Код выше инстанцировании новыйFirstViewModel каждый раз, когда это UserControl создается. Поэтому, когда элемент управления получает , созданный по ContentControl (на основе DataTemplate), он затем идет вперед, а также создает новый FirstViewModel.

Таким образом, решение здесь, чтобы удалить UserControl.DataContext декларацию в UserControl, и вы можете вместо этого установить DataContext в ContentControl к тому, что из вашего SelectedView.

<ContentPresenter Content="{Binding SelectedView}" 
        DataContext="{Binding SelectedView}"/> 

Для того, чтобы использовать несколько моделей просмотра с одной точки зрения, вы можете просто добавить еще один DataTemplate:

<DataTemplate DataType="{x:Type vm:ThirdViewModel}"> 
    <views:SecondView/> 
</DataTemplate> 

Для Design-Time данных (чтобы получить IntelliSense), вы можете сделать использование d:DataContext, как описано в статье this.

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

+0

Это не позволяет мне использовать intellisense при разработке пользовательского элемента управления (я думаю, это потому, что пользовательский элемент управления не знает, что он находится внутри 'ContentPresenter') – Yoav

+0

Я отредактировал свой ответ для получения дополнительной информации о как реализовать данные времени разработки с помощью 'd: DataContext =" ... "' –