2016-12-19 7 views
0

У меня есть структура пользовательского интерфейса, которая состоит из MainWindowViewModel и MainViewModel с тремя вкладками ViewModels. Я использую MVVMLight для создания экземпляров этих вкладок. Мне нужно передать строку из модели firstview в xaml, чтобы отобразить ее в моем представлении mainwindow. Когда я не использую MainWindowViewModel, он работает, но мой MainViewModel является частью MainWindowViewModel. Итак, мой вопрос: какой правильный способ инициализировать MainViewModel внутри MainWindowViewModel, чтобы я мог получить текстовое свойство со своей вкладки и отобразить его в моем окне?Иерархия ViewModel в wpf

Мои MainWindow.xaml

<Window 
x:Class="Tabs.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:local="clr-namespace:Tabs" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
Title="MainWindow" 
Width="525" 
Height="350" 
mc:Ignorable="d"> 
<Grid> 
    <TabControl 
     Width="340" 
     Height="202" 
     Margin="21,41,0,0" 
     HorizontalAlignment="Left" 
     VerticalAlignment="Top" 

     > 
     <TabItem Header="Page 1"> 
      <Grid Background="#FFE5E5E5" DataContext="{Binding MainViewModel.FirstViewModel}"> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="11*"/> 
        <ColumnDefinition Width="24*"/> 
        <ColumnDefinition Width="34*"/> 
        <ColumnDefinition Width="265*"/> 
       </Grid.ColumnDefinitions> 
       <TextBlock Height="100" Text="{Binding MainViewModel.FirstViewModel.Text}" Grid.ColumnSpan="4" Margin="0,37" /> 
      </Grid> 
     </TabItem> 
     <TabItem Header="Page 2"> 
      <Grid Background="#FFE5E5E5" DataContext="{Binding MainViewModel.SecondViewModel}"> 
       <TextBlock Height="100" Text="{Binding Text}" /> 
      </Grid> 
     </TabItem> 
     <TabItem Header="Page 3"> 
      <Grid Background="#FFE5E5E5" DataContext="{Binding MainViewModel.ThirdViewModel}"> 
       <TextBox Height="100" Text="{Binding Input}" /> 
      </Grid> 
     </TabItem> 
    </TabControl> 

</Grid> 

Код За

public partial class MainWindow : Window 
     { 
      public MainWindow() 
      { 
       InitializeComponent(); 
       DataContext = new MainWindowViewModel(); 
      } 
     } 

Мой MainWindowViewModel

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace Tabs.ViewModel 
{ 
    class MainWindowViewModel : INotifyPropertyChanged 
    { 
     private MainViewModel mainViewModel; 

     public MainWindowViewModel() 
     { 
      mainViewModel = new MainViewModel(); 

     } 

     public MainViewModel MainViewModel 
     { 
      get 
      { 
       return mainViewModel; 
      } 

      set 
      { 
       mainViewModel = value; 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 
} 

Мой MainViewModel

using GalaSoft.MvvmLight; 
using Tabs.ViewModel.Base; 

namespace Tabs.ViewModel 
{ 

    public class MainViewModel : ViewModelBase 
    { 

     public FirstViewModel FirstViewModel { get; set; } 
     public SecondViewModel SecondViewModel { get; set; } 
     public ThirdViewModel ThirdViewModel { get; set; } 
     public MainViewModel() 
     { 
      FirstViewModel = new FirstViewModel(); 
      FirstViewModel.Text = "ehe"; //all i need is to show 
      SecondViewModel = new SecondViewModel(); 
      ThirdViewModel = new ThirdViewModel(); 
     } 
    } 
} 

Мои FirstViewModel и текстовое поле, я на самом деле хочу, чтобы получить

public class FirstViewModel:BaseViewModel 
{ 
    private string _text; 

    public string Text 
    { 
     get { return _text; } 
     set { Set(() => Text, ref _text, value); } 
    } 

    public FirstViewModel() 
    { 

    } 
} 
+0

1. ** Все свойства свойств ** ** должны сообщать об изменении. 2. Bind Page 1 TextBlock to Text (поскольку вы устанавливаете DataContext на уровне Grid на FirstViewModel) –

+0

BTW Вы можете использовать силу IntelliSense, если вы наберете «{Binding Path = ... это очень полезно (не забудьте скомпилировать решение перед редактированием файла XAML) –

+0

Схватите Snoop, чтобы проверить ваши привязки во время выполнения. Вы сможете легко увидеть ошибки привязки и поток DataContext. – Will

ответ

4

Проблема в том, что вы имели в том, что в вашем TextBlock Text связывания существа следующим образом:

Text="{Binding MainViewModel.FirstViewModel.Text}" 

Как тот факт, что ваш TextBlock находится в сетке, которая имеет этот набор данных:

DataContext="{Binding MainViewModel.FirstViewModel}" 

Так эффективно, что происходит в том, что он ищет для текста в этом месте:

MainViewModel.FirstViewModel.MainViewModel.FirstViewModel.Text 

Поскольку DataContext вашего TextBlock ваш FirstViewModel, если вы идете Text="{Binding DataContext}" вы увидите это не так.
То, что вы хотите сделать, это просто пойти:

Text="{Binding Text}" 

Дополнительные примечания:

Причина этого заключается в том, потому что, когда вы идете Text="{Binding Text}" МОФ проверяет элементы тока DataContext, которые всегда будут одинаковыми как DataContext своего родителя, если он явно не установлен.

+0

Спасибо большое! Это помогло мне. чтобы сделать его немного сложным, добавив свойство объекта. Я также хотел бы знать, нужно ли использовать BaseViewmodel для TabControl для включения TabItems в качестве свойств? –

+0

Привет, Павел, если не все ваше мнение модели будут получены из BaseViewModel.Как правило, если вы используете подход MVVM, и ваши модели просмотра предоставляют свойства, которые должны использоваться/взаимодействовать с представлением, ваша модель просмотра должна обслуживать базу BaseViewModelm, так как она будет содержать функциональные возможности, которые позволяют взаимодействовать с вашими свойствами, то есть реализация интерфейса INotifyPropertyChanged , – Heinrich