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.
199 lines
6.9 KiB
199 lines
6.9 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.
|
|
/// Hides SingleSelectSubMenu main entry in ItemsCollection (Visibility Collapsed).
|
|
/// Sets the header of the SingleSelectSubMenu instance to the Title, which helps to identify sssm while debugging.
|
|
/// </summary>
|
|
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
// extract instance and guard null
|
|
if (d is not SingleSelectSubMenu sssm) { return; }
|
|
|
|
sssm.Visibility = Visibility.Collapsed;
|
|
sssm.Header = sssm.Title;
|
|
}
|
|
|
|
/// <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; }
|
|
|
|
// IMRPOVEMENT Delete currently associated values (using e.OldValue) from RegisteredSubItemsAndParent
|
|
// create and add title menu item
|
|
var titleMenuItem = new MenuItem
|
|
{
|
|
IsEnabled = false,
|
|
Header = sssm.Title
|
|
};
|
|
parent.Items.Add(titleMenuItem);
|
|
|
|
// 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
|
|
|
|
}
|
|
|