|
|
|
@ -3,122 +3,206 @@ using System.Linq; |
|
|
|
using System.Collections; |
|
|
|
using System.Collections; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.ComponentModel; |
|
|
|
using System.ComponentModel; |
|
|
|
using System.Diagnostics; |
|
|
|
|
|
|
|
using System.Globalization; |
|
|
|
using System.Globalization; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
|
|
|
|
using System.Windows; |
|
|
|
using System.Windows; |
|
|
|
using System.Windows.Controls; |
|
|
|
using System.Windows.Controls; |
|
|
|
using System; |
|
|
|
using System; |
|
|
|
using System.Printing; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace MultiTerm.Wpf.Controls; |
|
|
|
namespace MultiTerm.Wpf.Controls; |
|
|
|
|
|
|
|
|
|
|
|
public class SingleSelectSubMenu : MenuItem |
|
|
|
public class SingleSelectSubMenu : MenuItem |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
#region Static Properties |
|
|
|
public static Dictionary<MenuItem, SingleSelectSubMenu> RegisteredSubItemsAndParent = new Dictionary<MenuItem, SingleSelectSubMenu>(); |
|
|
|
public static Dictionary<MenuItem, SingleSelectSubMenu> RegisteredSubItemsAndParent = new Dictionary<MenuItem, SingleSelectSubMenu>(); |
|
|
|
|
|
|
|
#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 = |
|
|
|
public static readonly DependencyProperty OptionsSourceProperty = |
|
|
|
DependencyProperty.Register("OptionsSource", |
|
|
|
DependencyProperty.Register("OptionsSource", |
|
|
|
typeof(IEnumerable), |
|
|
|
typeof(IEnumerable), typeof(SingleSelectSubMenu), |
|
|
|
typeof(SingleSelectSubMenu), |
|
|
|
|
|
|
|
new PropertyMetadata(null, OnOptionsSourceChanged)); |
|
|
|
new PropertyMetadata(null, OnOptionsSourceChanged)); |
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty SelectedMenuItemProperty = |
|
|
|
public static readonly DependencyProperty SelectedMenuItemProperty = |
|
|
|
DependencyProperty.Register("SelectedMenuItem", |
|
|
|
DependencyProperty.Register("SelectedMenuItem", |
|
|
|
typeof(object), |
|
|
|
typeof(object), typeof(SingleSelectSubMenu), |
|
|
|
typeof(SingleSelectSubMenu), |
|
|
|
|
|
|
|
new PropertyMetadata(null, OnSelectedMenuItemPropertyChanged)); |
|
|
|
new PropertyMetadata(null, OnSelectedMenuItemPropertyChanged)); |
|
|
|
|
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
private static void OnSelectedMenuItemPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
|
|
|
#region Dotnet Properties |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// .NET Property for OptionsSource. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
[Bindable(true)] |
|
|
|
|
|
|
|
public IEnumerable OptionsSource |
|
|
|
{ |
|
|
|
{ |
|
|
|
var sssm = d as SingleSelectSubMenu; |
|
|
|
get { return (IEnumerable)GetValue(OptionsSourceProperty); } |
|
|
|
if (sssm != null) |
|
|
|
set { SetValue(OptionsSourceProperty, value); } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// .NET Property for SelectedMenuItem. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
[Bindable(true)] |
|
|
|
|
|
|
|
public object SelectedMenuItem |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(e.NewValue != null) |
|
|
|
get { return GetValue(SelectedMenuItemProperty); } |
|
|
|
|
|
|
|
set { SetValue(SelectedMenuItemProperty, value); } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// .NET Property for Title. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
[Bindable(false)] |
|
|
|
|
|
|
|
public string Title |
|
|
|
{ |
|
|
|
{ |
|
|
|
// get menu item with same name from registered items |
|
|
|
get { return (string)GetValue(TitleProperty); } |
|
|
|
MenuItem selectedMenuItem = null; |
|
|
|
set { SetValue(TitleProperty, value); } |
|
|
|
foreach (var item in RegisteredSubItemsAndParent) |
|
|
|
} |
|
|
|
|
|
|
|
#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 |
|
|
|
|
|
|
|
var sssm = d as SingleSelectSubMenu; |
|
|
|
|
|
|
|
if (sssm == null) { return; } |
|
|
|
|
|
|
|
// extract instance of new Value and guard null |
|
|
|
|
|
|
|
var menuItem = e.NewValue as MenuItem; |
|
|
|
|
|
|
|
if (menuItem == null) { 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(item.Key.Header.ToString(), e.NewValue.ToString(), true) == 0) |
|
|
|
if (String.Compare(associatedItem.Header.ToString(), menuItem.Header.ToString(), true) == 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
selectedMenuItem = item.Key; |
|
|
|
associatedItem.IsChecked = true; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// var selectedMenuItem = RegisteredSubItemsAndParent.Where(x => x.Key.Header == e.NewValue).FirstOrDefault(); |
|
|
|
|
|
|
|
if(selectedMenuItem != null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
selectedMenuItem.IsChecked = true; |
|
|
|
|
|
|
|
//OnAnyItemChecked(selectedMenuItem, new RoutedEventArgs()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <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 |
|
|
|
|
|
|
|
var sssm = d as SingleSelectSubMenu; |
|
|
|
|
|
|
|
if (sssm == null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
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) |
|
|
|
private static void OnOptionsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
// extract instance and guard null |
|
|
|
var sssm = d as SingleSelectSubMenu; |
|
|
|
var sssm = d as SingleSelectSubMenu; |
|
|
|
if(sssm != null) |
|
|
|
if (sssm == null) { return; } |
|
|
|
{ |
|
|
|
// extract parent instance of SSSM and guard null |
|
|
|
if(e.NewValue != null) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var parent = sssm.Parent as MenuItem; |
|
|
|
var parent = sssm.Parent as MenuItem; |
|
|
|
if(parent != null) |
|
|
|
if (parent == null) { 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) |
|
|
|
foreach (var item in (IEnumerable)e.NewValue) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var converter = new EnumDescriptionConverter(); |
|
|
|
// create new menu item |
|
|
|
var newItem = new MenuItem() |
|
|
|
var converter = new EnumDescriptionToMenuItemConverter(); |
|
|
|
{ |
|
|
|
var newMenuItem = (MenuItem)converter.Convert(item, typeof(MenuItem), new object(), CultureInfo.CurrentCulture); |
|
|
|
Header = converter.Convert(item, typeof(object), null, CultureInfo.CurrentCulture), |
|
|
|
newMenuItem.IsCheckable = true; |
|
|
|
IsCheckable = true |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
newItem.Checked += OnAnyItemChecked; |
|
|
|
|
|
|
|
RegisteredSubItemsAndParent.Add(newItem, sssm); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parent.Items.Add(newItem); |
|
|
|
// assign to event handler and register in dictionary |
|
|
|
Debug.WriteLine(item); |
|
|
|
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) |
|
|
|
private static void OnAnyItemChecked(object sender, RoutedEventArgs e) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
// extract sender menuItem and guard null |
|
|
|
var menuItem = sender as MenuItem; |
|
|
|
var menuItem = sender as MenuItem; |
|
|
|
if(menuItem != null) |
|
|
|
if (menuItem == null) { return; } |
|
|
|
{ |
|
|
|
|
|
|
|
Debug.WriteLine($"menuitem checked: {menuItem}"); |
|
|
|
// get associated menu items |
|
|
|
|
|
|
|
var associatedMenuitems = GetAssociatedMenuItems(menuItem); |
|
|
|
|
|
|
|
|
|
|
|
// uncheck others |
|
|
|
foreach (var associatedItem in associatedMenuitems) |
|
|
|
foreach (var item in RegisteredSubItemsAndParent) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
if (item.Key != null && item.Key != menuItem) |
|
|
|
// uncheck items that are not null and not the sender item |
|
|
|
|
|
|
|
if (associatedItem != null && associatedItem != menuItem) |
|
|
|
{ |
|
|
|
{ |
|
|
|
item.Key.IsChecked = false; |
|
|
|
associatedItem.IsChecked = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// set menu item for respective parent |
|
|
|
// update SelectedMenuItem for respective parent |
|
|
|
RegisteredSubItemsAndParent[menuItem].SelectedMenuItem = menuItem; |
|
|
|
GetParentSingleSelectSubMenu(menuItem).SelectedMenuItem = menuItem; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[Bindable(true)] |
|
|
|
#region Helpers |
|
|
|
public IEnumerable OptionsSource |
|
|
|
private static IEnumerable<MenuItem> GetAssociatedMenuItems(SingleSelectSubMenu sssm) |
|
|
|
{ |
|
|
|
{ |
|
|
|
get { return(IEnumerable)GetValue(OptionsSourceProperty); } |
|
|
|
List<MenuItem> menuItems = new(); |
|
|
|
set { SetValue(OptionsSourceProperty, value); } |
|
|
|
foreach(var item in RegisteredSubItemsAndParent.Where(x => x.Value == sssm)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
menuItems.Add(item.Key); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return menuItems; |
|
|
|
|
|
|
|
} |
|
|
|
[Bindable(true)] |
|
|
|
private static IEnumerable<MenuItem> GetAssociatedMenuItems(MenuItem menuItem) |
|
|
|
public object SelectedMenuItem |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
get { return GetValue(SelectedMenuItemProperty); } |
|
|
|
List<MenuItem> menuItems = new(); |
|
|
|
set { SetValue (SelectedMenuItemProperty, value); } |
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|