我知道这个问题经常出现,但是我想了解这一点,而不仅仅是复制代码。我有两个UserControls和一个MainWindow。我要实现的是简单的导航功能:按下按钮1->在内容控件中打开UserControl1。与UserControl2的按钮2相同。
这就是我得到的(虽然不多,但全部由我自己编码,如果出现问题,请原谅):
MainWindow.xaml:
<Window x:Class="gf_mvvmlight.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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:command="http://www.galasoft.ch/mvvmlight"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:gf_mvvmlight"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
DataContext="{Binding Main, Source={StaticResource Locator}}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<command:EventToCommand Command="{Binding LoadedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Button>switch to Page 2</Button>
<ContentControl Content="{Binding Page1View, Source={StaticResource Locator}}" />
</Grid>
Page1.xaml(Page2相同):
<UserControl x:Class="gf_mvvmlight.View.Page1View"
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:local="clr-namespace:gf_mvvmlight.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
DataContext="{Binding Path=Page1ViewModel, Source={StaticResource Locator}}">
<Grid>
<Label>orkpwefkwe99</Label>
</Grid>
ViewModelLocater.cs:
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<Page1ViewModel>();
SimpleIoc.Default.Register<Page2ViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public Page1ViewModel Page1View
{
get
{
return ServiceLocator.Current.GetInstance<Page1ViewModel>();
}
}
public Page2ViewModel Page2View
{
get
{
return ServiceLocator.Current.GetInstance<Page2ViewModel>();
}
}
所以我的问题是:按下按钮时,如何使ContentControl动态并打开Page2View?我没有任何代码,只是一些技巧:)
并且该程序应该能够切换每个类的视图!!!
预先感谢:)
答案 0 :(得分:1)
我个人从未见过使用视图模型定位器的任何令人信服的理由。我通常将其删除,在App.xaml中声明MainViewModel的实例,并在DataContext="{StaticResource MainViewModel}"
的MainWindow中引用它。
无论是否使用ViewModelLocator,都可以使用DataTemplates填充视图。因此,在MainViewModel中,我通常会执行以下操作:
private BasePage _CurrentPage;
public BasePage CurrentPage
{
get { return this._CurrentPage; }
set
{
if (this._CurrentPage != value)
{
this._CurrentPage = value;
RaisePropertyChanged(() => this.CurrentPage);
}
}
}
然后我将BasePage子类化为不同的页面类型,即PageViewModel1,PageViewModel2等。然后在xaml中,我的MainWindow如下所示:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:PageViewModel1}">
<views:PageView1 />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:PageViewModel2}">
<views:PageView2 />
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentPage}" />
...其中PageView1和PageView2是您的用户控件。因此,现在每当将CurrentPage设置为一个页面时,ContentControl就会使用适当的DataTemplate填充它。
请注意,仅仅因为我不使用ViewModelLocator并不意味着我不相信使用依赖注入,实际上恰恰相反。我只是认为这里不需要它,而且有比ViewModelLocator(即Ninject)更好的实现。
更新:根据下面的问题进一步阐明这一点...上面的示例暗示了3种视图模型:MainViewModel,PageViewModel1和PageViewModel2。我与DataTemplates一起发布的XAML应该在您的MainWindow上,它的DataContext设置为MainViewModel的实例。假设MainViewModel构造函数执行以下操作:
public MainViewModel()
{
this.CurrentPage = new PageViewModel1();
}
该行代码设置CurrentPage,如果您像我一样声明了它(即使用属性更改通知),则MainView中的ContentControl将自动填充PageView1控件的实例。之所以这样做,是因为1)ContentControl绑定到CurrentPage
属性,并且2)我设置了一个DataTemplate,该模板有效地说:“只要某内容的内容为PageViewModel1类型,我希望您使用PageView1用户控件。此外,这也很重要……将PageView1控件的DataContext设置为CurrentPage是什么(即PageViewModel1的实例),以便可以绑定到那里的属性。我们在屏幕上显示一个相应的视图模型,其中包含与该视图相关的所有逻辑。
现在,假设我们重构PageViewModel1和PageViewModel2以接受指向父级MainViewModel的指针,并假设响应按钮按下或执行以下操作:
this.MyParentMainViewModel.CurrentPage = new PageViewModel2()
该属性现在已更改,并且该框架将通过处理PageView1控件并将其替换为PageView2控件进行响应,该控件又将其DataContext设置为CurrentPage。因此,您已经“更改了页面”,但是您完全在视图模型层中完成了此操作,并依靠数据绑定和数据模板将这些更改自动传播到视图层。
这显然是一个非常非常简单的示例,我仅用于说明DataTemplating的工作方式。实际上,子视图模型永远不会直接访问其父级,或者甚至永远不会了解它们,您通常会使用依赖项注入框架将接口传递给子级,然后由父级处理...。但这是另一个主题文章。 :)