2011-01-28 17 views
19

Szukałem rozwiązania w Internecie, ale nie udało mi się go znaleźć w mojej próbce. Potrzebuję dodać separator między elementem menu kontekstowego, które są generowane z kodu za. Próbowałem dodać to z takimi liniami kodu jak poniżej, ale bez powodzenia.Jak dodać poziomy separator do dynamicznie utworzonego kontekstowego menu?

this.Commands.Add(new ToolStripSeparator()); 

Zastanawiam się, czy ktoś może pomóc. Z góry dziękuję.

Context Menu XAML:

<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}"> 
    <Setter Property="ContextMenu"> 
     <Setter.Value> 
      <ContextMenu ItemsSource="{Binding Commands}"> 
       <ContextMenu.ItemContainerStyle> 
        <Style TargetType="{x:Type MenuItem}"> 
         <Setter Property="Command" Value="{Binding}" /> 
         <Setter Property="Header" Value="{Binding Path=Text}" /> 
         <Setter Property="CommandParameter" Value="{Binding Path=Parameter}" /> 
        </Style> 
       </ContextMenu.ItemContainerStyle> 
      </ContextMenu> 
     </Setter.Value> 
    </Setter> 

C#, które dodaje się w sposób:

this.Commands = new ObservableCollection<ICommand>(); 
     this.Commands.Add(MainWindow.AddRole1); 
     this.Commands.Add(MainWindow.AddRole2); 
     this.Commands.Add(MainWindow.AddRole3); 
     this.Commands.Add(MainWindow.AddRole4); 
     //this.Add(new ToolStripSeparator()); 
     this.Commands.Add(MainWindow.AddRole5); 
     this.Commands.Add(MainWindow.AddRole6); 
     this.Commands.Add(MainWindow.AddRole7); 

Odpowiedz

12

Albo, zamiast swoją ContextMenu wiążą się zbiór poleceń, powiązać go z kolekcją FrameworkElements następnie można dodać zarówno elementów menu lub Separatory bezpośrednio do kolekcji i niech kontroli Menu zrobić wszystko templating. ...

<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}"> 
    <Setter Property="ContextMenu"> 
     <Setter.Value> 
      <ContextMenu ItemsSource="{Binding Commands}" /> 
     </Setter.Value> 
    </Setter> 
</Style> 

C#:

this.Commands = new ObservableCollection<FrameworkElement>(); 

this.Commands.Add(new MenuItem {Header = "Menuitem 2", Command = MainWindow.AddRole1}); 
this.Commands.Add(new MenuItem {Header = "Menuitem 2", Command = MainWindow.AddRole2}); 
this.Commands.Add(new MenuItem {Header = "Menuitem 3", Command = MainWindow.AddRole3}); 
this.Commands.Add(new MenuItem {Header = "Menuitem 4", Command = MainWindow.AddRole4}); 

this.Commands.Add(new Separator); 

this.Commands.Add(new MenuItem {Header = "Menuitem 5", Command = MainWindow.AddRole5}); 
this.Commands.Add(new MenuItem {Header = "Menuitem 6", Command = MainWindow.AddRole6}); 
this.Commands.Add(new MenuItem {Header = "Menuitem 7", Command = MainWindow.AddRole7}); 

Wystarczy stosować to podejście w moim app - separator wygląda lepiej w ten sposób również.

+0

Dziękuję za udostępnienie tej techniki. – vladc77

+12

Nie jest to świetny pomysł, jeśli chcesz zachować separację widoku modelu. –

+0

Nie wiem, dlaczego. Ten kod znajduje się w ViewModel, więc jest oddzielny od widoku.Wartość True zawiera kontrolki interfejsu użytkownika związane z widokiem, a jeśli chcesz je wyłączyć z ViewModel, możesz umieścić całą funkcjonalność w zachowaniu i mieć to powiązanie z listą poleceń dla elementów menu z fałszywym poleceniem dla separatora. – samneric

40

Zrobiłem to raz i używane null jak mój separatora. Z XAML, ja wtedy stylem szablon użyć separatora jeśli DataContext była zerowa

Kod za:

this.Commands.Add(MainWindow.AddRole4); 
this.Add(null); 
this.Commands.Add(MainWindow.AddRole5); 

XAML było coś takiego:

<ContextMenu.ItemContainerStyle> 
    <Style TargetType="{x:Type MenuItem}"> 
     <Setter Property="Command" Value="{Binding}" /> 
     <Setter Property="Header" Value="{Binding Path=Text}" /> 
     <Setter Property="CommandParameter" Value="{Binding Path=Parameter}" /> 

     <Style.Triggers> 
      <DataTrigger Binding="{Binding }" Value="{x:Null}"> 
       <Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" /> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</ContextMenu.ItemContainerStyle> 

Nadzieja mam składnię po prawej - Nie mam IDE na tym komputerze, aby zweryfikować kod:

EDYTOWANIE

Oto przykładowy szablon dla separatora menu kontekstowego. Umieszczam go w ContextMenu.Resources, chociaż możesz umieścić go w dowolnym miejscu w aplikacji, o ile tylko ContextMenu ma do niego dostęp.

<ContextMenu.Resources> 
    <ControlTemplate x:Key="MenuSeparatorTemplate"> 
     <Separator /> 
    </ControlTemplate> 
</ContextMenu.Resources> 
+0

Dziękuję za pomysł. Jednak to jeszcze nie działa. Nie mogę jeszcze wstawić separatora. Zmieniłem wartość na "Wartość =" {DynamicResource MenuSeparatorTemplate} "" i mogłem debugować rozwiązanie. W wyniku tego separator nie jest widoczny i obszar ten ma stan przewrócenia nad pustym menuitem. Zastanawiam się, czy można to naprawić. – vladc77

+0

Musisz utworzyć "MenuSeparatorTemplate". Ponieważ nie jest on tworzony, nic nie jest pokazywane. – Rachel

+0

Jak uzyskać dostęp do ogólnego szablonu Separator z datatriggera? – vladc77

0

Zastosowanie ItemTemplateSelector:

public class MenuItemTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate SeparatorTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     var menuItem = container.GetVisualParent<MenuItem>(); 
     if (menuItem == null) 
     { 
      throw new Exception("Unknown MenuItem type"); 
     } 

     if (menuItem.DataContext == null) 
     { 
      return SeparatorTemplate; 
     } 

     return menuItem.ItemTemplate; 
    } 
} 

Xaml:

<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" 

           ItemsSource="{Binding Path=ViewContentMenuItems}" > 
           <ContextMenu.ItemTemplateSelector> 
            <templateSelectors:MenuItemTemplateSelector> 
             <templateSelectors:MenuItemTemplateSelector.SeparatorTemplate> 
              <DataTemplate> 
               <Separator /> 
              </DataTemplate> 
             </templateSelectors:MenuItemTemplateSelector.SeparatorTemplate> 
            </templateSelectors:MenuItemTemplateSelector> 
           </ContextMenu.ItemTemplateSelector> 
          </ContextMenu> 

W modelu

public ObservableCollection<MenuItem> ViewContentMenuItems 
    { 
     get 
     { 
      var temp = new ObservableCollection<MenuItem>(); 
      temp.Add(null); 
      temp.Add(CreateFolderMenuItem); 
      return temp; 
     } 
    } 
private MenuItem CreateFolderMenuItem 
    { 
     get 
     { 
      var createFolderMenuItem = new MenuItem() 
      { 
       Header = "New Folder", 
       Icon = new Image 
       { 
        Source = new BitmapImage(new Uri("/icons/folderWinCreate.png", UriKind.Relative)), 
        Height = 16, 
        Width = 16 
       } 
      }; 

      Message.SetAttach(createFolderMenuItem, "CreateDocumentsFolder");//Caliburn example 
      return createFolderMenuItem; 
     } 
    } 
+0

Nie umieszczaj elementów View w modelu widoku, a tym bardziej modelu. – aaronburro

0

Aby to zrobić poprawnie MVVM trzeba zdefiniować własny interfejs elementu (feIMenuItem), tworzenia klas pochodnych do Menu/ContextMenu i MenuItem, w tych klasach przesłonić po wirtualnych chronionych metod:

ItemsControl.PrepareContainerForItemOverride 
ItemsControl.ClearContainerForItemOverride 
ItemsControl.GetContainerForItemOverride 
ItemsControl.IsItemItsOwnContainerOverride 

zapewnić, że metody tworzenia dla elementy kontenerów typu IMenuItem Twojego nowego produktu pochodnego od MenuItem Typ z powiązaniem wszystkich potrzebnych właściwości, tutaj można rozróżnić różne typy IMenuItem, aby wyświetlić zwykłe elementy, separatory lub niektóre cienie inne. W przypadku nieznanych typów wywołaj podstawową implementację.

Teraz, jeśli będzie wiązać ItemsSource własność nowego pochodzącego z Menu/ContextMenu sterowania z kolekcji IMenuItem, pokaże oczekiwany rezultat bez konieczności teraz Widok- rzeczy po stronie ViewModel.

2

Mam zmodyfikowane rozwiązanie dostarczone przez Rachel powyżej, aby poprawić styl separatora. Rozumiem, że ten post jest stary, ale nadal jest jednym z najlepszych wyników w Google. W mojej sytuacji używałam go do Menu kontra Menu kontekstowe, ale to samo powinno działać.

XAML

<Menu ItemsSource="{Binding MenuItems}"> 
    <Menu.Resources> 
     <ControlTemplate x:Key="MenuSeparatorTemplate"> 
      <Separator> 
       <Separator.Style> 
        <Style TargetType="{x:Type Separator}" BasedOn="{StaticResource ResourceKey={x:Static MenuItem.SeparatorStyleKey}}"/> 
       </Separator.Style> 
      </Separator> 
     </ControlTemplate> 
     <Style TargetType="{x:Type MenuItem}"> 
      <Setter Property="Header" Value="{Binding MenuItemHeader}" /> 
      <Setter Property="Command" Value="{Binding MenuItemCommand}" /> 
      <Setter Property="CommandParameter" Value="{Binding MenuItemCommandParameter}" /> 
      <Setter Property="ItemsSource" Value="{Binding MenuItemCollection}" /> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding }" Value="{x:Null}"> 
        <Setter Property="Template" Value="{StaticResource MenuSeparatorTemplate}" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Menu.Resources> 
</Menu> 

Without Separator Style Change

With Separator Style Change

+1

Witamy w Stack Overflow! Wygląda na to, że jest to najlepsza odpowiedź, więc zalecam usunięcie części o komentarzach i dodanie kontekstu, aby było to kompletne rozwiązanie. –

Powiązane problemy