You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.2 KiB
148 lines
5.2 KiB
using MultiTerm.Wpf.ValueConverters;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System;
|
|
|
|
namespace MultiTerm.Wpf.Controls;
|
|
|
|
public class CommandableSubMenu : MenuItem
|
|
{
|
|
#region Static Properties
|
|
private static readonly Dictionary<MenuItem, CommandableSubMenu> RegisteredSubItemsAndParent = new();
|
|
#endregion
|
|
|
|
#region Dependency Properties
|
|
public static readonly DependencyProperty TitleProperty =
|
|
DependencyProperty.Register("Title",
|
|
typeof(string), typeof(CommandableSubMenu),
|
|
new PropertyMetadata(String.Empty, OnTitleChanged));
|
|
|
|
public static readonly DependencyProperty OptionsSourceProperty =
|
|
DependencyProperty.Register("OptionsSource",
|
|
typeof(IEnumerable), typeof(CommandableSubMenu),
|
|
new PropertyMetadata(null, OnOptionsSourceChanged));
|
|
|
|
public static readonly DependencyProperty CommandParameterTypeProperty =
|
|
DependencyProperty.Register("CommandParameterType",
|
|
typeof(Type), typeof(CommandableSubMenu),
|
|
new PropertyMetadata(null, OnCommandParameterTypePropertyChanged));
|
|
#endregion
|
|
|
|
#region Dotnet Properties
|
|
/// <summary>
|
|
/// .NET Property for OptionsSource.
|
|
/// </summary>
|
|
[Bindable(true)]
|
|
public IEnumerable OptionsSource
|
|
{
|
|
get { return (IEnumerable)GetValue(OptionsSourceProperty); }
|
|
set { SetValue(OptionsSourceProperty, value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// .NET Property for Title.
|
|
/// </summary>
|
|
[Bindable(false)]
|
|
public string Title
|
|
{
|
|
get { return (string)GetValue(TitleProperty); }
|
|
set { SetValue(TitleProperty, value); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// .NET Property for CommandParameterType.
|
|
/// </summary>
|
|
[Bindable(false)]
|
|
public Type CommandParameterType
|
|
{
|
|
get { return (Type)GetValue(CommandParameterTypeProperty); }
|
|
set { SetValue(CommandParameterTypeProperty, value);}
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Title Changed Handler.
|
|
/// Disables CommandableSubMenu and sets header to title.
|
|
/// </summary>
|
|
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
// extract instance and guard null
|
|
if (d is not CommandableSubMenu csm) { return; }
|
|
|
|
csm.Header = csm.Title;
|
|
csm.IsEnabled = true;
|
|
}
|
|
|
|
private static void OnCommandParameterTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
// nothing to do
|
|
}
|
|
|
|
/// <summary>
|
|
/// Options Source Changed Handler.
|
|
/// Builds list with options and adds them to parent ItemsControl (must be subtype of ItemsControl).
|
|
/// Registers menu Items in locally stored list.
|
|
/// Cannot handle changing OptionsSources. Internal list will build up.
|
|
/// </summary>
|
|
private static void OnOptionsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
// extract instance and guard null
|
|
if (d is not CommandableSubMenu csm) { return; }
|
|
// extract parent instance of CSM and guard null
|
|
if (csm.Parent is not ItemsControl parent) { throw new ArgumentException($"Wrong parent type."); }
|
|
|
|
// iterate through new OptionsSource Values and build up list of menuItems
|
|
foreach (var item in (IEnumerable)e.NewValue)
|
|
{
|
|
// create new menu item
|
|
var converter = new EnumDescriptionToMenuItemConverter();
|
|
var newMenuItem = (MenuItem)converter.Convert(item, typeof(MenuItem), new object(), CultureInfo.CurrentCulture);
|
|
newMenuItem.IsCheckable = false;
|
|
|
|
// assign to event handler and register in dictionary
|
|
newMenuItem.Click += OnAnyItemClicked;
|
|
RegisteredSubItemsAndParent.Add(newMenuItem, csm);
|
|
|
|
// add to parent (which is expected to be a menu item)
|
|
parent.Items.Add(newMenuItem);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event handler that handles registered menu items being clicked.
|
|
/// </summary>
|
|
/// <param name="sender">MenuItem that was clicked</param>
|
|
/// <param name="e">routed event args</param>
|
|
private static void OnAnyItemClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
// extract sender menuItem and guard null
|
|
if (sender is not MenuItem menuItem) { return; }
|
|
|
|
// get parent csm
|
|
var parentCsm = GetParentCommandableSubMenu(menuItem);
|
|
if (parentCsm.CommandParameterType == null)
|
|
{
|
|
throw new Exception($"'OnAnyItemClicked()' Parent CommandableSubMenu has Property {nameof(CommandParameterType)} not set.");
|
|
}
|
|
|
|
// convert back to enum type
|
|
var converter = new EnumDescriptionToMenuItemConverter();
|
|
var enumValue = (Enum)converter.ConvertBack(menuItem, parentCsm.CommandParameterType, new object(), CultureInfo.CurrentCulture);
|
|
|
|
// run command if not null
|
|
parentCsm.Command?.Execute(enumValue);
|
|
}
|
|
|
|
#region Helpers
|
|
private static CommandableSubMenu GetParentCommandableSubMenu(MenuItem menuItem)
|
|
{
|
|
return RegisteredSubItemsAndParent[menuItem];
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|