Control for menu Item collection
A simple CustomControl for using collection in MenuItem with another MenuItem
from article : https://www.codeproject.com/Articles/22834/MenuItems-Collections-within-a-MenuItem
opriginal source code : MenuItems_Src

CustomControl
public class MenuItemCollection : MenuItem
{
static MenuItemCollection()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MenuItemCollection), new FrameworkPropertyMetadata(typeof(MenuItemCollection)));
}
#region Constructor & OnApplyTemplate
public MenuItemCollection() { }
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
#endregion
#region Dependency Property
//public static readonly DependencyProperty IsCheckedBindingPathProperty = DependencyProperty.Register(
// "IsCheckedBindingPath", typeof(String), typeof(MenuItemCollection), new PropertyMetadata(""));
//public String IsCheckedBindingPath
//{
// get { return (String)GetValue(IsCheckedBindingPathProperty); }
// set { SetValue(IsCheckedBindingPathProperty, value); }
//}
#region TopSeparatorVisibility (DP SHORT)
public Visibility TopSeparatorVisibility { get { return (Visibility)GetValue(TopSeparatorVisibilityProperty); } set { SetValue(TopSeparatorVisibilityProperty, value); } }
public static readonly DependencyProperty TopSeparatorVisibilityProperty = DependencyProperty.Register("TopSeparatorVisibility", typeof(Visibility), typeof(MenuItemCollection), new PropertyMetadata(Visibility.Collapsed));
#endregion
#region BottomSeparatorVisibility (DP SHORT)
public Visibility BottomSeparatorVisibility { get { return (Visibility)GetValue(BottomSeparatorVisibilityProperty); } set { SetValue(BottomSeparatorVisibilityProperty, value); } }
public static readonly DependencyProperty BottomSeparatorVisibilityProperty = DependencyProperty.Register("BottomSeparatorVisibility", typeof(Visibility), typeof(MenuItemCollection), new PropertyMetadata(Visibility.Collapsed));
#endregion
#region SelectCommand (DP SHORT)
public ICommand SelectCommand { get { return (ICommand)GetValue(SelectCommandProperty); } set { SetValue(SelectCommandProperty, value); } }
public static readonly DependencyProperty SelectCommandProperty = DependencyProperty.Register("SelectCommand", typeof(ICommand), typeof(MenuItemCollection), new PropertyMetadata(null));
#endregion
#endregion
}
public class SepartorVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
try
{
Visibility v = (Visibility)values[0];
if (v == Visibility.Visible)
{
v = (int)values[1] == 0 ? Visibility.Collapsed : v;
}
return v;
}
catch { }
return Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and style in generic.xaml
<!-- MENU ITEM COLLECTION -->
<Style TargetType="{x:Type local:MenuItemCollection}">
<Style.Resources>
<local:SepartorVisibilityConverter x:Key="sepconv" />
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MenuItemCollection}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<Separator>
<Separator.Visibility>
<MultiBinding Converter="{StaticResource sepconv}">
<Binding Path="TopSeparatorVisibility"
RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="ItemsSource.Count"
RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</Separator.Visibility>
</Separator>
<ItemsControl ItemsSource="{TemplateBinding ItemsSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding .}"
HeaderTemplate="{Binding HeaderTemplate, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MenuItemCollection}}}"
Command="{Binding SelectCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MenuItemCollection}}}"
CommandParameter="{Binding .}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Separator >
<Separator.Visibility>
<MultiBinding Converter="{StaticResource sepconv}">
<Binding Path="BottomSeparatorVisibility"
RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="ItemsSource.Count"
RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</Separator.Visibility>
</Separator>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
for using
<local:MenuItemCollection ItemsSource="{Binding Items}"
SelectCommand="{Binding SelectCommand}"
TopSeparatorVisibility="Visible"
BottomSeparatorVisibility="Visible" />
<local:MenuItemCollection ItemsSource="{Binding Items2}"
SelectCommand="{Binding Select2Command}">
<local:MenuItemCollection.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</local:MenuItemCollection.HeaderTemplate>
</local:MenuItemCollection>
with in MVVM
// for binding
public ObservableCollection<string> Items { get; } = new ObservableCollection<string>();
public ObservableCollection<object> Items2 { get; } = new ObservableCollection<object>();
.....
// create
{
Items.Add("alpha");
Items.Add("beta");
Items.Add("gamma");
Items.Add("xxx");
Items.Add("yyy");
}
{
Items2.Add(new Item { Name = "alpha" });
Items2.Add(new Item { Name = "beta" });
Items2.Add(new Item { Name = "gamma" });
Items2.Add(new Item { Name = "xxx" });
Items2.Add(new Item { Name = "yyy" });
}
// Items class sample
public class Item
{
public string Name { get; set; }
}
// and command for binding
#region Select (receive string)
RelayCommand _SelectCommand;
public ICommand SelectCommand
{
get
{
if (_SelectCommand == null)
{
_SelectCommand = new RelayCommand(param => this.DoSelect(param),
param => CanSelect(param));
}
return _SelectCommand;
}
}
// can for Select
private bool CanSelect(object param)
{
return !param.Equals("beta");
}
// function for Select
private void DoSelect(object param)
{
Console.WriteLine("SELECT = " + param);
}
#endregion
#region Select2 (receive Item object)
RelayCommand _Select2Command;
public ICommand Select2Command
{
get
{
if (_Select2Command == null)
{
_Select2Command = new RelayCommand(param => this.DoSelect2(param),
param => CanSelect2(param));
}
return _Select2Command;
}
}
// can for Select2
private bool CanSelect2(object param)
{
return (param as Item)?.Name.Equals("alpha") ?? false;
}
// function for Select2
private void DoSelect2(object param)
{
Console.WriteLine("SELECT 2 = " + param);
}
#endregion
