8

我想用 MVVM 模式构建一个简单的应用程序。

此应用程序将有两个主要部分:

  • 顶部的菜单
  • 以下内容

导航将很简单:

  • 每个菜单项(例如“管理客户”或“查看报告”)都会在内容区域中填充一个具有某些特定功能的新页面

之前使用代码隐藏了代码,其中菜单项的代码隐藏事件处理程序已加载所有页面,并且应该显示的页面作为 StackPanel 的子项加载。但是,这在 MVVM 中不起作用,因为您不想手动填充 StackPanel 而是显示例如带有 DataTemplate 的“PageItem”对象等。

那么你们中的那些用 MVVM 制作了这样一个简单的单击菜单应用程序的人,你的基本应用程序结构是什么? 我在考虑这些方面:

MainView.xaml:

<DockPanel LastChildFill="False">

    <Menu 
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"/>

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

</DockPanel>

其中,Menu 填充了“PageItems”的集合,DataTemplate 将每个“PageItem 对象”的 Title 显示为每个 MenuItem 的 Header。

ContentControl 将填充具有完整功能的 View/ViewModel 对,但对此不确定。

4

3 回答 3

9

首先,我认为您应该保留代码隐藏事件处理程序,没有任何实际原因将简单的 2 行事件处理程序更改为复杂的命令驱动的怪物是没有意义的(不要说可测试性,这是主菜单,它每次运行应用程序时都会进行测试)。

现在,如果你确实想走纯 MVVM 路线,你所要做的就是让你的菜单触发一个命令,首先,在一些资源部分添加这个样式:

<Style x:Key="MenuItemStyle" TargetType="MenuItem">
    <Setter Property="Command" 
            Value="{Binding DataContext.SwitchViewCommand,
            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/>
    <Setter Property="CommandParameter" 
            Value="{Binding}"/>
</Style>

此样式将使菜单项在附加的视图模型上触发 SwitchViewCommand,并将 MenuItem 的 DataContext 作为命令参数。

实际视图与您的代码相同,只是将该样式作为 ItemContainerStyle 的附加引用(因此它适用于菜单项而不是 DataTemplate 的内容):

<DockPanel LastChildFill="False">

    <Menu DockPanel.Dock="Top"
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"
        ItemContainerStyle="{StaticResource MenuItemStyle}"/>
    <ContentControl 
    Content="{Binding SelectedPageItem}"/>
</DockPanel>

现在在您需要的视图模型中(我使用字符串,因为我没有您的 PageItem 代码):

private string _selectedViewItem;
public List<string> PageItemsMainMenu { get; set; }
public string SelectedPageItem
{
    get { return _selectedViewItem; }
    set { _selectedViewItem = value; OnNotifyPropertyChanged("SelectedPageItem"); }
}
public ICommand SwitchViewCommand { get; set; }

并使用您使用的任何命令类使命令调用此代码:

private void DoSwitchViewCommand(object parameter)
{
    SelectedPageItem = (string)parameter;
}

现在,当用户单击菜单项时,菜单项将调用 SwitchViewCommand,并将页面项作为参数。

该命令将调用将设置 SelectedPageItem 属性的 DoSwitchViewCommand

该属性将引发 NotifyPropertyChanged,这将使 UI 通过数据绑定进行更新。

或者,您可以编写一个 2 行事件处理程序,由您选择

于 2009-06-20T15:52:35.630 回答
0

我可以想象 VM 中有一个 ObservableCollection,它包含所有可从菜单调用的页面。然后将 ItemsControl 和 ContentControl 绑定到它,以使 ContentControl 始终显示该列表中的 CurrentItem。当然,菜单只会绑定到一些 Title 属性,而 ContentControl 会采用整个项目并根据类型插入一些适当的视图。

于 2009-06-20T13:47:57.897 回答
0

另一种选择是使用 ListBox 而不是菜单,将 ListBox 设置为看起来像菜单,然后您可以绑定到选定的值,如下所示:

<DockPanel LastChildFill="False">

    <ListBox 
        ItemsSource="{Binding PageItemsMainMenu}" 
        ItemTemplate="{StaticResource MainMenuStyle}"
        IsSynchronizedWithCurrentItem="True"/>

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

</DockPanel>

请注意 IsSynchronizedWithCurrentItem="True" 设置所选项目和 {Binding PageItemsMainMenu/} 与尾随斜杠使用它。

于 2009-06-20T16:25:43.033 回答