2009-07-01 62 views
15

當我綁定菜單項與一個ObservableCollection的菜單項的只有「內」區域是可點擊:如何將ViewModels的ObservableCollection綁定到MenuItem?

alt text http://tanguay.info/web/external/mvvmMenuItems.png

在我查看我有這樣的菜單:

<Menu> 
    <MenuItem 
     Header="Options" ItemsSource="{Binding ManageMenuPageItemViewModels}" 
       ItemTemplate="{StaticResource MainMenuTemplate}"/> 
</Menu> 

然後我用它綁定它DataTemplate

<DataTemplate x:Key="MainMenuTemplate"> 
    <MenuItem 
     Header="{Binding Title}" 
     Command="{Binding DataContext.SwitchPageCommand, 
     RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}" 
     Background="Red" 
     CommandParameter="{Binding IdCode}"/> 
</DataTemplate> 

由於每個視圖模型中的ObservableCollection ManageMenuPageItemViewModels有一個屬性標題IDCODE,上面的代碼工作正常一見鍾情。

無論其,問題是,菜單項在DataTemplate中實際上是內部另一個菜單項(,就好像它被綁定兩次),使得在與背景以上的DataTemplate =」紅色「有一個每個菜單項內的紅色框只有這個區域可以被點擊,而不是整個菜單項區域本身(例如,如果用戶點擊選中區域或右邊或左邊內部cl ickable區域,然後什麼也沒有發生,而如果你沒有一個單獨的顏色是非常混亂。)

什麼是的MenuItems結合的ViewModels的一個ObservableCollection使每個菜單項裏面的整個區域是正確的方法點擊?

UPDATE:

所以我做了基於以下建議如下更改,現在有這樣的:

alt text http://tanguay.info/web/external/mvvmMenuItemsYellow.png

我只有我的DataTemplate中TextBlock的,但我現在還不能「色全菜單項」,但只是將TextBlock:

<DataTemplate x:Key="MainMenuTemplate"> 
    <TextBlock Text="{Binding Title}"/> 
</DataTemplate> 

我把命令綁定到Menu.ItemCo ntainerStyle但他們現在不火:

<Menu DockPanel.Dock="Top"> 
    <Menu.ItemContainerStyle> 
     <Style TargetType="MenuItem"> 
      <Setter Property="Background" Value="Yellow"/> 
      <Setter Property="Command" Value="{Binding DataContext.SwitchPageCommand, 
     RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Menu}}}"/> 
      <Setter Property="CommandParameter" Value="{Binding IdCode}"/> 
     </Style> 
    </Menu.ItemContainerStyle> 
    <MenuItem 
     Header="MVVM" ItemsSource="{Binding MvvmMenuPageItemViewModels}" 
       ItemTemplate="{StaticResource MainMenuTemplate}"/> 
    <MenuItem 
     Header="Application" ItemsSource="{Binding ApplicationMenuPageItemViewModels}" 
       ItemTemplate="{StaticResource MainMenuTemplate}"/> 
    <MenuItem 
     Header="Manage" ItemsSource="{Binding ManageMenuPageItemViewModels}" 
       ItemTemplate="{StaticResource MainMenuTemplate}"/> 
</Menu> 

回答

35

我發現使用MVVM與MenuItems是非常具有挑戰性的。我的應用程序的其餘部分使用DataTemplates將視圖與ViewModel配對,但由於您描述的原因,這似乎不適用於菜單。這是我最終如何解決它的。我查看看起來是這樣的:

<DockPanel> 
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=(local:MainViewModel.MainMenu)}"> 
    <Menu.ItemContainerStyle> 
     <Style> 
      <Setter Property="MenuItem.Header" Value="{Binding Path=(contracts:IMenuItem.Header)}"/> 
      <Setter Property="MenuItem.ItemsSource" Value="{Binding Path=(contracts:IMenuItem.Items)}"/> 
      <Setter Property="MenuItem.Icon" Value="{Binding Path=(contracts:IMenuItem.Icon)}"/> 
      <Setter Property="MenuItem.IsCheckable" Value="{Binding Path=(contracts:IMenuItem.IsCheckable)}"/> 
      <Setter Property="MenuItem.IsChecked" Value="{Binding Path=(contracts:IMenuItem.IsChecked)}"/> 
      <Setter Property="MenuItem.Command" Value="{Binding}"/> 
      <Setter Property="MenuItem.Visibility" Value="{Binding Path=(contracts:IMenuItem.Visible), 
       Converter={StaticResource BooleanToVisibilityConverter}}"/> 
      <Setter Property="MenuItem.ToolTip" Value="{Binding Path=(contracts:IMenuItem.ToolTip)}"/> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Path=(contracts:IMenuItem.IsSeparator)}" Value="true"> 
        <Setter Property="MenuItem.Template"> 
         <Setter.Value> 
          <ControlTemplate TargetType="{x:Type MenuItem}"> 
           <Separator Style="{DynamicResource {x:Static MenuItem.SeparatorStyleKey}}"/> 
          </ControlTemplate> 
         </Setter.Value> 
        </Setter> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Menu.ItemContainerStyle> 
</Menu> 
</DockPanel> 

如果你注意到,我定義了名爲IMenuItem的接口,這是視圖模型的菜單項。以下是此代碼:

public interface IMenuItem : ICommand 
{ 
    string Header { get; } 
    IEnumerable<IMenuItem> Items { get; } 
    object Icon { get; } 
    bool IsCheckable { get; } 
    bool IsChecked { get; set; } 
    bool Visible { get; } 
    bool IsSeparator { get; } 
    string ToolTip { get; } 
} 

請注意,IMenuItem定義了IEnumerable項目,這是您如何獲得子菜單。此外,IsSeparator是一種在菜單中定義分隔符的方法(另一個棘手的小技巧)。如果IsSeparator爲true,您可以在xaml中看到它如何使用DataTrigger將樣式更改爲現有的分隔符樣式。以下是MainViewModel如何定義MainMenu屬性(視圖綁定到的):

public IEnumerable<IMenuItem> MainMenu { get; set; } 

這似乎很好。我假設你可以使用MainMenu的ObservableCollection。實際上,我使用MEF從部分組成菜單,但之後項目本身是靜態的(即使每個菜單項的屬性都不是)。我也使用一個實現IMenuItem的AbstractMenuItem類,它是一個輔助類來實例化各個部分中的菜單項。

UPDATE:

關於你的色差問題,確實this thread幫助?

14

不要把MenuItemDataTemplateDataTemplate定義MenuItem內容。相反,通過ItemContainerStyle指定MenuItem無關性:

<Menu> 
    <Menu.ItemContainerStyle> 
     <Style TargetType="MenuItem"> 
      <Setter Property="Header" Value="{Binding Title}"/> 
      ... 
     </Style> 
    </Menu.ItemContainerStyle> 
    <MenuItem 
     Header="Options" ItemsSource="{Binding ManageMenuPageItemViewModels}" 
       ItemTemplate="{StaticResource MainMenuTemplate}"/> 
</Menu> 

而且,看看HierarchicalDataTemplate秒。

+0

你的意思是在Menu.ItemContainerStyle中定義標題/顏色,然後在DataTemplate中放置一個定義Command和CommandParameter的HierarchicalDataTemplate? – 2009-07-01 08:47:32

+0

謝謝,這正是我一直在尋找的。很棒。謝謝! – 2010-05-04 20:06:06

+0

+1 - HierarchicalDataTemplates使得整個問題幾乎無關緊要。 – 2010-12-25 18:21:51

2

這是我如何完成我的菜單。這可能不是你所需要的,但我認爲它非常接近。

<Style x:Key="SubmenuItemStyle" TargetType="MenuItem"> 
    <Setter Property="Header" Value="{Binding MenuName}"></Setter> 
    <Setter Property="Command" Value="{Binding Path=MenuCommand}"/> 
    <Setter Property="ItemsSource" Value="{Binding SubmenuItems}"></Setter> 
    </Style> 

    <DataTemplate DataType="{x:Type systemVM:TopMenuViewModel}" > 
    <Menu> 
     <MenuItem Header="{Binding MenuName}"   
        ItemsSource="{Binding SubmenuItems}" 
        ItemContainerStyle="{DynamicResource SubmenuItemStyle}" /> 
    </Menu> 
    </DataTemplate> 

    <Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" /> 

TopMenuViewModel是將出現在菜單欄上的菜單的集合。它們每個都包含將要顯示的MenuName和一個名爲SubMenuItems的集合,我將其設置爲ItemsSource。

我通過樣式SumMenuItemStyle控制SubMenuItems的顯示方式。每個SubMenuItem都有其自己的MenuName屬性,類型爲ICommand的Command屬性以及可能的另一個SubMenuItems集合。

結果是,我能夠將所有菜單信息存儲在數據庫中,並動態地切換運行時顯示的菜單。整個菜單項區域可點擊並正確顯示。

希望這會有所幫助。

2

只要讓你的DataTemplate成爲一個TextBlock(或者可能是一個帶有圖標和TextBlock的堆棧面板)。

相關問題