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/SingleSelectSubMenu.cs

189 lines
6.5 KiB

using MultiTerm.Wpf.ValueConverters;
using System.Linq;
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 SingleSelectSubMenu : MenuItem
{
#region Static Properties
private static readonly Dictionary<MenuItem, SingleSelectSubMenu> RegisteredSubItemsAndParent = new();
#endregion
#region Dependency Properties
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title",
typeof(string), typeof(SingleSelectSubMenu),
new PropertyMetadata(String.Empty, OnTitleChanged));
public static readonly DependencyProperty OptionsSourceProperty =
DependencyProperty.Register("OptionsSource",
typeof(IEnumerable), typeof(SingleSelectSubMenu),
new PropertyMetadata(null, OnOptionsSourceChanged));
public static readonly DependencyProperty SelectedMenuItemProperty =
DependencyProperty.Register("SelectedMenuItem",
typeof(object), typeof(SingleSelectSubMenu),
new PropertyMetadata(null, OnSelectedMenuItemPropertyChanged));
#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 SelectedMenuItem.
/// </summary>
[Bindable(true)]
public object SelectedMenuItem
{
get { return GetValue(SelectedMenuItemProperty); }
set { SetValue(SelectedMenuItemProperty, value); }
}
/// <summary>
/// .NET Property for Title.
/// </summary>
[Bindable(false)]
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
#endregion
/// <summary>
/// SelectedMenuItem Property Changed Handler.
/// Updates IsChecked Property of according menu item.
/// </summary>
private static void OnSelectedMenuItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// extract instance and guard null
if (d is not SingleSelectSubMenu sssm) { return; }
// extract instance of new Value and guard null
if (e.NewValue is not MenuItem menuItem) { return; }
// get associated menu items (same group)
var associatedMenuitems = GetAssociatedMenuItems(sssm);
// check menu item with same name in same group
foreach (var associatedItem in associatedMenuitems)
{
if (String.Compare(associatedItem.Header.ToString(), menuItem.Header.ToString(), true) == 0)
{
associatedItem.IsChecked = true;
break;
}
}
}
/// <summary>
/// Title Changed Handler.
/// Disables SingleSelectSubMenu and sets header to title.
/// </summary>
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// extract instance and guard null
if (d is not SingleSelectSubMenu sssm) { return; }
sssm.Header = sssm.Title;
sssm.IsEnabled = false;
}
/// <summary>
/// Options Source Changed Handler.
/// Builds list with options and adds them to parent MenuItem (must be Menu Item!).
/// 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 SingleSelectSubMenu sssm) { return; }
// extract parent instance of SSSM and guard null
if (sssm.Parent is not MenuItem parent) { return; }
// 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 = true;
// assign to event handler and register in dictionary
newMenuItem.Checked += OnAnyItemChecked;
RegisteredSubItemsAndParent.Add(newMenuItem, sssm);
// add to parent (which is expected to be a menu item)
parent.Items.Add(newMenuItem);
}
}
/// <summary>
/// Event handler that handles registered menu items being checked.
/// </summary>
/// <param name="sender">MenuItem that was checked</param>
/// <param name="e">routed event args</param>
private static void OnAnyItemChecked(object sender, RoutedEventArgs e)
{
// extract sender menuItem and guard null
if (sender is not MenuItem menuItem) { return; }
// get associated menu items
var associatedMenuitems = GetAssociatedMenuItems(menuItem);
foreach (var associatedItem in associatedMenuitems)
{
// uncheck items that are not null and not the sender item
if (associatedItem != null && associatedItem != menuItem)
{
associatedItem.IsChecked = false;
}
}
// update SelectedMenuItem for respective parent
GetParentSingleSelectSubMenu(menuItem).SelectedMenuItem = menuItem;
}
#region Helpers
private static IEnumerable<MenuItem> GetAssociatedMenuItems(SingleSelectSubMenu sssm)
{
List<MenuItem> menuItems = new();
foreach(var item in RegisteredSubItemsAndParent.Where(x => x.Value == sssm))
{
menuItems.Add(item.Key);
}
return menuItems;
}
private static IEnumerable<MenuItem> GetAssociatedMenuItems(MenuItem menuItem)
{
List<MenuItem> menuItems = new();
SingleSelectSubMenu parent = GetParentSingleSelectSubMenu(menuItem);
foreach (var item in RegisteredSubItemsAndParent.Where(x => x.Value == parent))
{
menuItems.Add(item.Key);
}
return menuItems;
}
private static SingleSelectSubMenu GetParentSingleSelectSubMenu(MenuItem menuItem)
{
return RegisteredSubItemsAndParent[menuItem];
}
#endregion
}