【问题标题】:WPF Mvvm navigation with parameters带参数的 WPF Mvvm 导航
【发布时间】:2015-08-03 07:22:13
【问题描述】:

按照this tutorial(以及其他)并阅读此处提出的问题,我构建了一个导航机制,允许我在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; }
}

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

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

【问题讨论】:

  • "如果我想明确地将DataContext 添加到视图中" - 你能提供一个例子来说明你是如何实现这一点的吗?

标签: c# wpf mvvm navigation


【解决方案1】:

这里的问题是您将DataContext 设置在您的UserControl 中,也在您的主视图模型中。

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

上面的代码会在每次创建UserControl 时实例化一个new 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>

对于Design-Time数据(获取智能感知),您可以使用d:DataContext,如this 文章中所述。

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

【讨论】:

  • 这不让我在设计用户控件的时候使用智能感知(我猜是因为用户控件不知道他在ContentPresenter里面)
  • 我已经编辑了我的答案,以获取有关如何使用 d:DataContext="..." 实现设计时数据的更多信息
猜你喜欢
  • 2023-03-07
  • 1970-01-01
  • 2016-07-29
  • 1970-01-01
  • 1970-01-01
  • 2015-06-04
  • 2013-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多