バインディングを使用して動的メニューを作成しようとしています。私のビューモデルには、ヘッダーとコマンドを含むオブジェクトのリストがあります。ただし、機能していません。問題はデータテンプレートにあると思います。以下の私のコードを参照してください:
<Menu Background="{x:Null}" Grid.Row="0" Grid.Column="1" Panel.ZIndex="2" Width="865" Height="85" HorizontalAlignment="Left" ItemsSource="{Binding Path=MenuItems}">
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="MenuItemViewModel" ItemsSource="{Binding Path=MenuItems}">
<MenuItem Header="{Binding Header}" Style="{DynamicResource MenuItemStyle1}" ItemsSource="{Binding Path=MenuItems}" Padding="10,12,10,0" Height="44.1" Margin="30,0,0,0" FontWeight="Bold">
<MenuItem.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</MenuItem.ItemsPanel>
</MenuItem>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Header}" Style="{DynamicResource MenuItemStyle1}" Padding="0,8,0,0" Height="38">
</MenuItem>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
結果には最初のメニューのみが表示されます。サブメニューは表示されませんが、子があるメニュー、メニューヘッダーの後に矢印が印刷されるため、サブメニューは表示されます。
バインディングで何か間違っているものを見つけることができますか?または何か提案はありますか?
情報を提供するためだけに、MenuItemsはMenuItemsと呼ばれるMenuItemViewModelオブジェクト(サブメニュー)のヘッダーとリストを持つMenuItemViewModelオブジェクトのリストです。
私にとっては、このシンプルなテンプレートで動作しました:
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
<TextBlock Text="{Binding Header}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
完全な例は次のとおりです。
MainWindow.xaml:
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication14"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
<TextBlock Text="{Binding Header}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
<Grid>
</Grid>
</DockPanel>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace WpfApplication14
{
public partial class MainWindow : Window
{
public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
public MainWindow()
{
InitializeComponent();
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Alpha" },
new MenuItemViewModel { Header = "Beta",
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Beta1" },
new MenuItemViewModel { Header = "Beta2",
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Beta1a" },
new MenuItemViewModel { Header = "Beta1b" },
new MenuItemViewModel { Header = "Beta1c" }
}
},
new MenuItemViewModel { Header = "Beta3" }
}
},
new MenuItemViewModel { Header = "Gamma" }
};
DataContext = this;
}
}
public class MenuItemViewModel
{
private readonly ICommand _command;
public MenuItemViewModel()
{
_command = new CommandViewModel(Execute);
}
public string Header { get; set; }
public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
public ICommand Command
{
get
{
return _command;
}
}
private void Execute()
{
// (NOTE: In a view model, you normally should not use MessageBox.Show()).
MessageBox.Show("Clicked at " + Header);
}
}
public class CommandViewModel : ICommand
{
private readonly Action _action;
public CommandViewModel(Action action)
{
_action = action;
}
public void Execute(object o)
{
_action();
}
public bool CanExecute(object o)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
}
}
結果のウィンドウは次のようになります。
それは非常に簡単です、ネストされたメニューにこのコードを使用できます
ViewModel:TopMenuViewModel.cs
public partial class TopMenuViewModel
{
public TopMenuViewModel()
{
TopMenuItems = new ObservableCollection<MenuItem>
{
new MenuItem
{
Title = "File",
PageName =typeof(OfficeListView).FullName,
ChildMenuItems= {
new MenuItem
{
Title = "New"
},
new MenuItem
{
Title = "Open"
},
new MenuItem
{
Title = "Save"
}
}
},
new MenuItem
{
Title = "Edit"
},
new MenuItem
{
Title = "Search"
}
};
}
ビュー:TopMenuView.xaml
<Menu IsMainMenu="True" ItemsSource="{Binding TopMenuItems}">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Title}"/>
<Setter Property="ItemsSource" Value="{Binding Path=ChildMenuItems}"/>
</Style>
</Menu.ItemContainerStyle>
</Menu>