MVVM の原則に厳密に準拠しようとしている WPF アプリケーションを構築しています。メニューを正しくレンダリングするのに問題があります。私はいくつかのアプローチを試みましたが、行き詰まっています。私のバインディングは正しいようですが、スタイルの操作についてはわかりません。
これが私が問題を抱えているコードです。私が言ったように、バインドは適切なようで、Snoop を使用してヘッダー メニュー項目の正しい値を確認することもできますが、表示されるのはメニュー項目の空のコンテナーだけです。
<DockPanel>
<DockPanel.Resources>
<HierarchicalDataTemplate x:Key="TopMenuHDT" ItemsSource="{Binding Children}">
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="Header" Value="{Binding MenuText}" />
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding MenuIcon}" Height="16px" Width="16px" />
</Setter.Value>
</Setter>
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
</HierarchicalDataTemplate>
</DockPanel.Resources>
<Menu DockPanel.Dock="Top" Height="auto"
ItemsSource="{Binding TopMenuItems}"
ItemTemplate="{StaticResource TopMenuHDT}"/>
私のメインViewModelでは:
private ObservableCollection<MenuViewModel> _topMenuItems;
public ObservableCollection<MenuViewModel> TopMenuItems
{
get { return _topMenuItems; }
set
{
if (_topMenuItems == value)
return;
_topMenuItems = value; base.RaisePropertyChanged("TopMenuItems");
}
}
...
public void LoadMainMenu()
{
IList<ViewModels.MenuViewModel> fileMenuItems = PopulateFileMenuEntries();
IList<ViewModels.MenuViewModel> editMenuItems = PopulateEditMenuEntries();
_topMenuItems.Add(new ViewModels.MenuViewModel() { MenuText = "_File", Children = new ObservableCollection<ViewModels.MenuViewModel>(fileMenuItems) });
_topMenuItems.Add(new ViewModels.MenuViewModel() { MenuText = "_Edit", Children = new ObservableCollection<ViewModels.MenuViewModel>(editMenuItems) });
private IList<ViewModels.MenuViewModel> PopulateFileMenuEntries()
{
List<ViewModels.MenuViewModel> fileMenuItems = new List<ViewModels.MenuViewModel>();
fileMenuItems.Add(new ViewModels.MenuViewModel() { MenuText = "_Open", MenuIcon = new BitmapImage(new Uri("pack://application:,,,/Resources/OpenDocument16.png")) , Command = _mainWindowViewModel.OpenCommand });
fileMenuItems.Add(new ViewModels.MenuViewModel() { MenuText = "Open _Recent" });
return fileMenuItems;
}
メニュービューモデル:
public class MenuViewModel : ObservableObject
{
internal MenuViewModel()
{
IsEnabled = true;
}
private string _menuText;
public string MenuText
{
get { return _menuText; }
set
{
if (_menuText == value)
return;
_menuText = value; base.RaisePropertyChanged("MenuText");
}
}
private ICommand _command;
public ICommand Command
{
get { return _command; }
set
{
if (_command == value)
return;
_command = value; base.RaisePropertyChanged("Command");
}
}
private BitmapImage _menuIcon;
public BitmapImage MenuIcon
{
get { return _menuIcon; }
set
{
if (_menuIcon == value)
return;
_menuIcon = value; base.RaisePropertyChanged("MenuIcon");
}
}
private ObservableCollection<MenuViewModel> _children;
public ObservableCollection<MenuViewModel> Children
{
get { return _children; }
set
{
_children = value; base.RaisePropertyChanged("Children");
}
}
}
これを正しくレンダリングするための助けをいただければ幸いです。
編集:
誰かがこの同様の問題に遭遇した場合の最終的な解決策は次のとおりです。
<DockPanel>
<Menu DockPanel.Dock="Top" Height="auto" ItemsSource="{Binding TopMenuItems}" >
<Menu.Resources>
<Image x:Key="MenuIconResource" Height="16" Width="16" Source="{Binding MenuIcon}" x:Shared="False" />
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="Header" Value="{Binding MenuText}" />
<Setter Property="InputGestureText" Value="{Binding ShortcutText}" />
<Setter Property="IsEnabled" Value="{Binding IsEnabled}" />
<Setter Property="Icon" Value="{StaticResource MenuIconResource}" />
<Setter Property="ItemsSource" Value="{Binding Children}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding }" Value="{x:Null}">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate>
<Separator Style="{StaticResource {x:Static MenuItem.SeparatorStyleKey}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.Resources>
</Menu>