Multiprocotol Terminalprogram (BAT)
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.
MultiTerm/MultiTerm.Wpf/Controls/CommandableSubMenu.cs

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
}