![](/img/trans.png)
[英]Dynamic Context Menu XAML where items are located into an observablecollection
[英]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.