带绑定的 MVVM 菜单栏

She*_*wad 3 c# wpf mvvm

如何创建遵循 MVVM 模式的菜单栏以及如何将视图模型绑定到 xaml

我为单个项目创建了项目视图模型和菜单列表视图模型来收集单个项目

项目视图模型文件

/// <summary>
/// Menu item viewModel
/// </summary>
public class MenuItemViewModel : BaseViewModel
{
    #region Public Properties

    /// <summary>
    /// The displayed name
    /// </summary>
    public string Header { get; set; }

    /// <summary>
    /// The item order
    /// </summary>
    public int Order { get; set; }

    /// <summary>
    /// True if this item is Enabled
    /// </summary>
    public bool IsEnabled { get; set; }

    /// <summary>
    /// True if this item is currently selected
    /// </summary>        
    public bool IsSelected { get; set; }

    /// <summary>
    /// The item icon
    /// </summary>        
    public string Icon { get; set; }

    /// <summary>
    /// The parent view model.
    /// </summary>        
    public MenuListViewModel Parent { get; set; }

    #endregion

    #region Public Commands

    /// <summary>
    /// The command for when the item is clicked
    /// </summary>
    public ICommand OpenCommand { get; set; }


    #endregion

    #region Constructor
    /// <summary>
    /// Default constructor
    /// </summary>
    public MenuItemViewModel()
    {
        // Create commands
        OpenCommand = new RelayCommand(ItemCommand);
    } 
    #endregion

    #region Command Methods

    /// <summary>
    /// When the item is clicked 
    /// </summary>
    public virtual void ItemCommand() { }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

菜单列表视图模型文件

/// <summary>
/// Sub Menu item viewModel
/// </summary>
public class MenuListViewModel : BaseViewModel
{

    #region Protected Members

    /// <summary>
    /// The items list
    /// </summary>
    protected ObservableCollection<MenuItemViewModel> mItemsChildren;

    /// <summary>
    /// The items list
    /// </summary>
    protected ObservableCollection<Action> mChildrenCommands;

    /// <summary>
    /// The subMenu list
    /// </summary>
    protected ObservableCollection<MenuListViewModel> mSubMentChildren;

    #endregion

    #region Public Properties

    /// <summary>
    /// The displayed name
    /// </summary>
    public string Header { get; set; }

    /// <summary>
    /// True if this item is Enabled
    /// </summary>

    public bool IsEnabled { get; set; }

    /// <summary>
    /// True if this item is currently selected
    /// </summary>        
    public bool IsSelected { get; set; }

    /// <summary>
    /// The item icon
    /// </summary>        
    public object Icon { get; set; }

    /// <summary>
    /// The menu order
    /// </summary>
    public int Order { get; set; }

    /// <summary>
    /// The parent view model.
    /// </summary>
    public MenuListViewModel ParentViewModel { get; set; }

    /// <summary>
    /// The items list
    /// </summary>
    public ObservableCollection<MenuItemViewModel> Items
    {
        get => mItemsChildren;
        set
        {
            // Make sure list has changed
            if (mItemsChildren == value)
                return;

            // Update value
            mItemsChildren = value;
        }
    }

    /// <summary>
    /// The items list
    /// </summary>
    public ObservableCollection<Action> ItemsCommands
    {
        get => mChildrenCommands;
        set
        {
            // Make sure list has changed
            if (mChildrenCommands == value)
                return;

            // Update value
            mChildrenCommands = value;
        }
    }

    /// <summary>
    /// The subMenu items for the list
    /// </summary>
    public ObservableCollection<MenuListViewModel> SubMenuItems
    {
        get => mSubMentChildren;
        set
        {
            // Make sure list has changed
            if (mSubMentChildren == value)
                return;

            // Update value
            mSubMentChildren = value;
        }
    }

    #endregion

    public virtual void LoadChildMenuItems()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

Xaml 文件

<UserControl.Resources>
    <Style TargetType="{x:Type MenuItem}">
        <Setter Property="Header" Value="{Binding Path=Header}"/>
        <Setter Property="Command" Value="{Binding Path=Command}"/>
    </Style>
    <HierarchicalDataTemplate 
    DataType="{x:Type local:MenuBarViewModel}"
    ItemsSource="{Binding Path=Items}">
    </HierarchicalDataTemplate>
</UserControl.Resources>

<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=Items}"/>
Run Code Online (Sandbox Code Playgroud)

那么如何在 xaml 文件中添加这个 viewModles 并将它们绑定到 Headers 和命令

And*_*ndy 7

您的 MenuItemViewModel 中没有集合项。分层数据模板的工作方式是将子菜单的项源绑定到父项的属性。既然你没有那个,那么最好的情况就是你只是获得了顶级水平。

这是一些简化的标记和代码:

    <Menu ItemsSource="{Binding MenuItems}" Height="30">
        <Menu.Resources>
            <Style TargetType="{x:Type MenuItem}">
                <Setter Property="Header" Value="{Binding Path=Header}"/>
                <Setter Property="Command" Value="{Binding Path=Command}"/>
            </Style>
            <HierarchicalDataTemplate 
                 DataType="{x:Type local:MenuItemVM}"
                 ItemsSource="{Binding SubItems}">
            </HierarchicalDataTemplate>
        </Menu.Resources>
    </Menu>
Run Code Online (Sandbox Code Playgroud)

在我的窗口视图模型中,我设置了一些基本数据:

    private ObservableCollection<MenuItemVM> menuItems = new ObservableCollection<MenuItemVM>(
        new List<MenuItemVM>
        {
            new MenuItemVM{ Header="File", SubItems= new ObservableCollection<MenuItemVM>( new List<MenuItemVM>
            {
                new MenuItemVM{ Header="Open"},
                new MenuItemVM{ Header="Save"}
            })
            }
        }

        );
Run Code Online (Sandbox Code Playgroud)

还有我简化的 menuitemvm:

public class MenuItemVM
{
    public string Header { get; set; }
    public ICommand Command { get; set; }
    public ObservableCollection<MenuItemVM> SubItems { get; set; }
}
Run Code Online (Sandbox Code Playgroud)