如图样:
View结构
MainView(MainViewModel)
|---Guide1View(Guide1ViewModel)
|---Guide2View(Guide2ViewModel)
|---Guide2_1View1(Guide2_1ViewModel)
|---Guide2_1View2(Guide2_1ViewModel)
ViewModel实例结构
Main(ViewModelViewModel)
|---CurrentViewModel(GuidePageViewModelBase)
|---PageViewModelList(ObservableCollection<GuidePageViewModelBase>)
|---Guide1(Guide1ViewModel)
|---Guide2(Guide2ViewModel)
|---LVM1(LViewModel)
|---LVM2(LViewModel)
1、通过ContentControl显示选中的视图模型对应的视图:
<ContentControl Content="{Binding CurrentViewModel}"> <ContentControl.Resources> <DataTemplate DataType="{x:Type viewmodel:Guide1ViewModel}"> <view:Guide1View/> </DataTemplate> <DataTemplate DataType="{x:Type viewmodel:Guide2ViewModel}"> <view:Guide2View/> </DataTemplate> </ContentControl.Resources> </ContentControl>
2、Guide2_1View作为一个多次使用的控件,对应一个LViewModel,设置自己的DataContext(这里的背景是该视图的使用个数确定的。当然也可以用ListBox代替):
<view:Guide2_1View DataContext="{Binding Path=DataContext.LVM1,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> <view:Guide2_1View DataContext="{Binding Path=DataContext.LVM2,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
完整代码:
ViewModel:
using GalaSoft.MvvmLight; namespace WPF_NestedVMAndView.ViewModel { public class MainViewModel : ViewModelBase { public MainViewModel() { PageViewModelList = new ObservableCollection<GuidePageViewModelBase>() { new Guide1ViewModel(), new Guide2ViewModel(), }; CurrentViewModel = PageViewModelList[1]; } public const string CurrentViewModelPropertyName = "CurrentViewModel"; private GuidePageViewModelBase _currentViewModel; public GuidePageViewModelBase CurrentViewModel { get { return _currentViewModel; } set { if (_currentViewModel == value) return; _currentViewModel = value; RaisePropertyChanged(CurrentViewModelPropertyName); } } public const string PageViewModelListPropertyName = "PageViewModelList"; private ObservableCollection<GuidePageViewModelBase> _pageViewModelList; public ObservableCollection<GuidePageViewModelBase> PageViewModelList { get { return _pageViewModelList; } set { if (_pageViewModelList == value) return; _pageViewModelList = value; RaisePropertyChanged(PageViewModelListPropertyName); } } } public class GuidePageViewModelBase : ViewModelBase { public GuidePageViewModelBase(string name) { Name = name; } public const string NamePropertyName = "Name"; private string _name; public string Name { get { return _name; } set { if (_name == value) return; _name = value; RaisePropertyChanged(NamePropertyName); } } } public class Guide1ViewModel : GuidePageViewModelBase { public Guide1ViewModel() : base("Guide1") { } } public class Guide2ViewModel : GuidePageViewModelBase { public Guide2ViewModel() : base("Guide2") { LVM1 = new LViewModel() { Text = "LVM1", }; LVM2 = new LViewModel() { Text = "LVM2", }; } public const string LVM1PropertyName = "LVM1"; private LViewModel _lvm1; public LViewModel LVM1 { get { return _lvm1; } set { if (_lvm1 == value) return; _lvm1 = value; RaisePropertyChanged(LVM1PropertyName); } } public const string LVM2PropertyName = "LVM2"; private LViewModel _lvm2; public LViewModel LVM2 { get { return _lvm2; } set { if (_lvm2 == value) return; _lvm2 = value; RaisePropertyChanged(LVM2PropertyName); } } } public class LViewModel : ViewModelBase { public const string TextPropertyName = "Text"; private string _text; public string Text { get { return _text; } set { if (_text == value) return; _text = value; RaisePropertyChanged(TextPropertyName); } } } }
MainView:
<Window x:Class="WPF_NestedVMAndView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:view="clr-namespace:WPF_NestedVMAndView.View" xmlns:viewmodel="clr-namespace:WPF_NestedVMAndView.ViewModel" Title="MainWindow" Height="350" Width="525" DataContext="{Binding Main,Source={StaticResource Locator}}"> <DockPanel Margin="20"> <ListBox ItemsSource="{Binding PageViewModelList}" DisplayMemberPath="Name" SelectedItem="{Binding CurrentViewModel}" DockPanel.Dock="Left" Width="100"/> <ContentControl Content="{Binding CurrentViewModel}"> <ContentControl.Resources> <DataTemplate DataType="{x:Type viewmodel:Guide1ViewModel}"> <view:Guide1View/> </DataTemplate> <DataTemplate DataType="{x:Type viewmodel:Guide2ViewModel}"> <view:Guide2View/> </DataTemplate> </ContentControl.Resources> </ContentControl> </DockPanel> </Window>
Guide1View:
<UserControl x:Class="WPF_NestedVMAndView.View.Guide1View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" Background="White" > <Grid> <TextBlock Text="{Binding Name}" Margin="10"/> </Grid> </UserControl>
Guide2View:
<UserControl x:Class="WPF_NestedVMAndView.View.Guide2View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:view="clr-namespace:WPF_NestedVMAndView.View" mc:Ignorable="d" Background="White"> <DockPanel> <TextBlock Text="{Binding Name}" Margin="10" DockPanel.Dock="Top"/> <view:Guide2_1View DataContext="{Binding Path=DataContext.LVM1,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" DockPanel.Dock="Top"/> <view:Guide2_1View DataContext="{Binding Path=DataContext.LVM2,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" DockPanel.Dock="Top"/> </DockPanel> </UserControl>
Guide2_1View:
<UserControl x:Class="WPF_NestedVMAndView.View.Guide2_1View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" Background="White"> <Grid> <TextBlock Text="{Binding Text}" Margin="10"/> </Grid> </UserControl>
。