簡體   English   中英

混合動態和靜態XAML菜單項

[英]Mixing dynamic and static XAML menu items

我有一個場景,我需要有靜態和動態菜單項。 靜態項目將在XAML中定義,動態的項目由View Model提供。 每個動態項本身都由VieModel表示,我們稱之為CommandViewModel。 CommandViewModel除其他外還有顯示名稱,它還可以包含其他CommandViewModel。

用作菜單的datacontext的MainViewModel如下:

public class MainMenuViewModel : INotifyPropertyChanged
{

  private ObservableCollection<CommandViewModel> m_CommandVMList;


  public MainMenuViewModel()
  {
    m_ CommandVMList = new ObservableCollection<CommandViewModel>();

    CommandViewModel cmv = new CommandViewModel();
    cmv.DisplayName = "Dynamic Menu 1";
    m_CommandVMList.Add(cmv);

    cmv = new CommandViewModel();
    cmv.DisplayName = "Dynamic Menu 2";
    m_CommandVMList.Add(cmv);

    cmv = new CommandViewModel();
    cmv.DisplayName = "Dynamic Menu 3";
    m_CommandVMList.Add(cmv);

  }

  public ObservableCollection<CommandViewModel> CommandList
  {
    get { return m_CommandVMList; }
    set
    {
      m_CommandVMList = value;
      OnPropertyChanged("CommandList");
    }
  }

...... ......

菜單XAML:

<Grid>
  <Grid.Resources>
    <HierarchicalDataTemplate DataType="{x:Type Fwf:CommandViewModel}" ItemsSource="{Binding Path=CommandViewModels}">
      <MenuItem Header="{Binding Path=DisplayName}"/>
    </HierarchicalDataTemplate>
  </Grid.Resources>

  <Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
    <MenuItem Header="Static Top Menu Item 1">
      <MenuItem Header="Static Menu Item 1"/>
        <MenuItem Header="Static Menu Item 2"/>
        <MenuItem Header="Static Menu Item 3"/>
        <ItemsControl ItemsSource="{Binding Path= CommandList}"/>
        <MenuItem Header="Static Menu Item 4"/>
      </MenuItem>
  </Menu>
</Grid>

一切正常,除了我試圖表示動態菜單列表,在這種情況下,它在UI上顯示為包含更多菜單項的ONE菜單項,因此當您單擊時,整個動態菜單項集合都會被選中在項目上。 正確表示集合,因為每個動態菜單項都顯示為菜單項本身,但在此更大的菜單項中。 我想我明白為什么因為菜單只是為每個包含的項目創建一個菜單項,靜態或動態它並不關心。 有沒有辦法讓每個動態菜單項在同一級別上創建並屬於父菜單項,就像示例中的靜態菜單項一樣?

我不會在XAML端硬編碼“靜態”菜單項,而是將它們作為CommandViewModel對象在VM端硬編碼。

由於您無論采用哪種方式進行硬編碼,都不會失去靈活性,如果您選擇在將來以不同方式呈現靜態菜單項,您將獲得保持靜態菜單項與HierarchicalDataTemplate同步的額外好處。

請注意,您可能需要更改綁定,以便菜單綁定到一組菜單項。 你可以在這里找到一個例子。

編輯:代碼示例

我能夠相當快地破解它,並且大多數類定義都是不完整的(例如INotifyPropertyChanged),但它應該讓你知道你可以做什么。 我在第三個命令上添加了一些命令嵌套,以確保Hierarchical DataTemplate正常工作。

這是XAML

<Window
    x:Class="WPFDynamicMenuItems.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFDynamicMenuItems"
    Title="Window1" Height="300" Width="600">
    <Grid>
        <Grid.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:CommandViewModel}" ItemsSource="{Binding Path=CommandList}">
                <ContentPresenter
                    Content="{Binding Path=DisplayName}"
                    RecognizesAccessKey="True" />
            </HierarchicalDataTemplate>
        </Grid.Resources>
        <ToolBarTray>
            <ToolBar>
            <Menu>
                <Menu.ItemsSource>
                    <CompositeCollection>
                        <MenuItem Header="A"></MenuItem>
                        <MenuItem Header="B"></MenuItem>
                        <MenuItem Header="C"></MenuItem>

                        <CollectionContainer x:Name="dynamicMenuItems">
                        </CollectionContainer>

                        <MenuItem Header="D"></MenuItem>

                    </CompositeCollection>
                </Menu.ItemsSource>

            </Menu>
                </ToolBar>
        </ToolBarTray>
    </Grid>
</Window>

這是代碼隱藏的代碼:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace WPFDynamicMenuItems
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private MainMenuViewModel _mainMenuVM = new MainMenuViewModel();

        public Window1()
        {
            InitializeComponent();

            this.dynamicMenuItems.Collection = this._mainMenuVM.CommandList;
        }
    }


    public class MainMenuViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<CommandViewModel> m_CommandVMList;

        public MainMenuViewModel()
        {
            m_CommandVMList = new ObservableCollection<CommandViewModel>();
            CommandViewModel cmv = new CommandViewModel();
            cmv.DisplayName = "Dynamic Menu 1";
            m_CommandVMList.Add(cmv);
            cmv = new CommandViewModel();
            cmv.DisplayName = "Dynamic Menu 2";
            m_CommandVMList.Add(cmv);
            cmv = new CommandViewModel();
            cmv.DisplayName = "Dynamic Menu 3";
            m_CommandVMList.Add(cmv);

            CommandViewModel nestedCMV = new CommandViewModel();
            nestedCMV.DisplayName = "Nested Menu 1";
            cmv.CommandList.Add(nestedCMV);

            nestedCMV = new CommandViewModel();
            nestedCMV.DisplayName = "Nested Menu 2";
            cmv.CommandList.Add(nestedCMV);
        }
        public ObservableCollection<CommandViewModel> CommandList
        {
            get { return m_CommandVMList; }
            set { m_CommandVMList = value; OnPropertyChanged("CommandList"); }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            //  Hook up event...
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

    public class CommandViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<CommandViewModel> m_CommandVMList;

        public CommandViewModel()
        {
            this.m_CommandVMList = new ObservableCollection<CommandViewModel>();
        }

        public string DisplayName { get; set; }

        public ObservableCollection<CommandViewModel> CommandList
        {
            get { return m_CommandVMList; }
            set { m_CommandVMList = value; OnPropertyChanged("CommandList"); }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            //  Hook up event...
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM