【问题标题】:WPF MVVM navigate viewsWPF MVVM 导航视图
【发布时间】:2013-11-08 09:01:52
【问题描述】:

我有一个包含多个视图的 WPF 应用程序。我想从视图 1 切换到视图 2,然后我可以切换到多个视图。所以我想要视图 1 上的一个按钮,在同一个窗口中加载 view2。

我尝试了这些方法,但无法正常工作。

从第一个链接看,问题是我看不懂 ViewModelLocator 代码。他们调用了CreateMain(); 函数,但它在哪里定义,以及如何从视图内部切换到另一个视图。

【问题讨论】:

  • @AndrasSebö,在这种情况下,我不同意你的看法。虽然我承认这不是一个好问题,但我看到的情况更糟,而且我相信用户的目标很清楚。
  • 那么问题是:如何从视图内部切换视图。
  • 您找到解决此问题的好方法了吗?
  • 我最终使用了 magellan 框架。对于具有大量导航的应用来说,这是一个很棒的框架。
  • @user2499088,请添加答案并接受。如果此问题没有可接受的答案,则此问题的重复项不能作为重复项关闭。请遵循帮助中心 What should I do when someone answers my question?What does it mean when an answer is "accepted"? 页面上的指南。

标签: c# wpf mvvm navigation


【解决方案1】:

首先,您不需要任何这些工具包/框架来实现 MVVM。它可以像这样简单......假设我们有一个MainViewModelPersonViewModel 和一个CompanyViewModel,每个都有自己的相关视图,每个都扩展了一个abstract 基类BaseViewModel

BaseViewModel 中,我们可以添加公共属性和/或ICommand 实例并实现INotifyPropertyChanged 接口。由于它们都扩展了BaseViewModel 类,我们可以在MainViewModel 类中拥有这个属性,可以将其设置为我们的任何视图模型:

public BaseViewModel ViewModel { get; set; }

当然,与此快速示例不同,您将在 your 属性上正确实现 INotifyPropertyChanged 接口。现在在App.xaml 中,我们声明了一些简单的DataTemplates 来连接视图和视图模型:

<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
    <Views:MainView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:PersonViewModel}">
    <Views:PersonView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:CompanyViewModel}">
    <Views:CompanyView />
</DataTemplate>

现在,无论我们在应用程序中使用我们的BaseViewModel 实例之一,这些DataTemplates 将告诉框架改为显示相关视图。我们可以这样显示它们:

<ContentControl Content="{Binding ViewModel}" />

所以我们现在要切换到新视图所需要做的就是从MainViewModel 类中设置ViewModel 属性:

ViewModel = new PersonViewModel();

最后,我们如何从其他视图中更改视图?有几种可能的方法可以做到这一点,但最简单的方法是将子视图中的Binding 直接添加到MainViewModel 中的ICommand。我使用自定义版本的RelayComand,但你可以使用任何你喜欢的类型,我猜你会得到图片:

public ICommand DisplayPersonView
{
    get { return new ActionCommand(action => ViewModel = new PersonViewModel(), 
        canExecute => !IsViewModelOfType<Person>()); }
}

在子视图 XAML 中:

<Button Command="{Binding DataContext.DisplayPersonView, RelativeSource=
    {RelativeSource AncestorType={x:Type MainView}}, Mode=OneWay}" />

就是这样!享受吧。

【讨论】:

  • 好吧,如果您使用的是 MVVM Light,那么您可能应该坚持使用他们用来做这些事情的任何东西……我的意思是您不需要需要使用框架来实现此功能。
  • 我不确定我是否真的理解你的问题@ETG87。视图模型类只是扩展BaseViewModel 类的类,视图只是UserControls。
  • 老兄,您需要阅读有关 XAML Namespaces and Namespace Mapping for WPF XAML...视图模型在 AppName.ViewModels 命名空间中声明,因此映射到 ViewModels 的 XAML 命名空间前缀。不应该有 BaseViewModel 命名空间,因为那是一个类,而不是命名空间。
  • @Sheridan,我在我的应用程序中执行此操作,但即使我在代码中创建了 ViewModel 的新实例,XAML 代码也会创建另一个实例。有没有办法解决这个问题?我正在尝试切换视图并立即绑定到一个事件,但由于 XAML 创建了一个新实例,我无法实现它。
  • @AUSTX_RJL,如果您还没有,您应该为此提出一个新问题。
【解决方案2】:

当我第一次开始使用 MVVM 时,我还为不同的 MVVM 框架特别是导航部分而苦苦挣扎。因此,我使用我发现的这个小教程,Rachel Lim 创建了。非常好,解释清楚。

在以下链接中查看它:

希望对你有所帮助:)

【讨论】:

  • 谢谢,但这不是我的意思。我将此示例用于另一个应用程序,但对于此应用程序,我没有侧面菜单。所以我在 view1 上有一个按钮,当我点击该按钮时,它必须切换到 view2
【解决方案3】:

也许this 链接会对您有所帮助。只需将NavigateTo 属性设置为您需要在窗口上显示的视图。

作为一个例子,你可以做类似的事情

<Window x:Class="MainWindowView" 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:meffed="http:\\www.codeplex.com\MEFedMVVM"
                                 meffed:ViewModelLocator.NonSharedViewModel="YourViewModel"
                                 WindowStartupLocation="CenterScreen">

    <Button meffed:NavigationExtensions.NavigateTo="firstview"
                    meffed:NavigationExtensions.NavigationHost="{Binding ElementName=_viewContainer}"
                    meffed:NavigationExtensions.NavigateOnceLoaded="False"
                    Visibility="Visible" />

    <ContentControl x:Name="_viewContainer" Margin="0,0,0,10" />
<Window>

那么类文件就是

public partial class MainWindowView : Window
{
    public MainWindowView()
    {           
              InitializeComponent();
    }

        public ContentControl ViewContainer { get { return _viewContainer; } }

    }

然后您可以将每个视图定义为UserControl,然后使用我上面给出的链接绑定按钮的meffed:NavigationExtensions.NavigateTo="secondView"。要定位WindowContentControl,只需使用RelativeSource 绑定。例如

meffed:NavigationExtensions.NavigationHost="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}},Path=ViewContainer}"

在每个视图中只看到您使用[NavigationView("firstview")] 等注释类定义后面的代码。

第一次很复杂,但是一旦你理解了这个想法就会很容易。

【讨论】:

    【解决方案4】:
    <ContentControl x:Name="K.I.S.S" Content="{Binding ViewModel, Converter={StaticResource ViewLocator}}"/>
    

    【讨论】:

      猜你喜欢
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多