带有参数的 WPF Mvvm 导航

本文关键字:Mvvm 导航 WPF 参数 | 更新日期: 2023-09-27 18:06:06

按照本教程(以及其他内容(并阅读此处提出的问题,我构建了一个导航机制,该机制将允许我在ViewModels之间传递参数:
对象库 - 每个视图模型都继承自它:

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; }
}

主视图模型 - 负责导航:

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显式添加到视图中以便像这样使用智能感知:

<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事件传递的参数。

带有参数的 WPF Mvvm 导航

这里的问题是您在UserControl 中以及主视图模型中设置DataContext

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

上面的代码在每次创建此UserControl时都会实例化一个新FirstViewModel。因此,当控件由ContentControl创建(基于DataTemplate(时,它将继续并创建一个新FirstViewModel

因此,这里的解决方案是删除UserControl中的UserControl.DataContext声明,您可以改为将ContentControlDataContext设置为SelectedView的。

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

为了将多个视图模型用于单个视图,您只需添加另一个DataTemplate

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

对于设计时数据(获取智能感知(,可以使用本文中所述的d:DataContext

这将需要您将一些视图模型设置为静态资源,我建议您在单独的ResourceDictionary中创建它们。