|
|
|
@ -12,6 +12,10 @@ namespace MultiTerm.Wpf.Controls; |
|
|
|
|
|
|
|
|
|
|
|
public class SingleSelectSubMenu : MenuItem |
|
|
|
public class SingleSelectSubMenu : MenuItem |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Internal marker for when internal unchecking is ongoing. Unchecking events shall then be ignored. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
private bool internalUncheckingOngoing = false; |
|
|
|
#region Static Properties |
|
|
|
#region Static Properties |
|
|
|
private static readonly Dictionary<MenuItem, SingleSelectSubMenu> RegisteredSubItemsAndParent = new(); |
|
|
|
private static readonly Dictionary<MenuItem, SingleSelectSubMenu> RegisteredSubItemsAndParent = new(); |
|
|
|
#endregion |
|
|
|
#endregion |
|
|
|
@ -31,6 +35,11 @@ public class SingleSelectSubMenu : MenuItem |
|
|
|
DependencyProperty.Register("SelectedMenuItem", |
|
|
|
DependencyProperty.Register("SelectedMenuItem", |
|
|
|
typeof(object), typeof(SingleSelectSubMenu), |
|
|
|
typeof(object), typeof(SingleSelectSubMenu), |
|
|
|
new PropertyMetadata(null, OnSelectedMenuItemPropertyChanged)); |
|
|
|
new PropertyMetadata(null, OnSelectedMenuItemPropertyChanged)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty AllowNoneSelectedProperty = |
|
|
|
|
|
|
|
DependencyProperty.Register("AllowNoneSelected", |
|
|
|
|
|
|
|
typeof(bool), typeof(SingleSelectSubMenu), |
|
|
|
|
|
|
|
new PropertyMetadata(false, OnAllowNoneSelectedPropertyChanged)); |
|
|
|
#endregion |
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
#region Dotnet Properties |
|
|
|
#region Dotnet Properties |
|
|
|
@ -63,6 +72,16 @@ public class SingleSelectSubMenu : MenuItem |
|
|
|
get { return (string)GetValue(TitleProperty); } |
|
|
|
get { return (string)GetValue(TitleProperty); } |
|
|
|
set { SetValue(TitleProperty, value); } |
|
|
|
set { SetValue(TitleProperty, value); } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// .NET Property for AllowNoneSelected. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
[Bindable(false)] |
|
|
|
|
|
|
|
public bool AllowNoneSelected |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
get { return (bool)GetValue(AllowNoneSelectedProperty); } |
|
|
|
|
|
|
|
set { SetValue(AllowNoneSelectedProperty, value); } |
|
|
|
|
|
|
|
} |
|
|
|
#endregion |
|
|
|
#endregion |
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
/// <summary> |
|
|
|
@ -127,6 +146,7 @@ public class SingleSelectSubMenu : MenuItem |
|
|
|
|
|
|
|
|
|
|
|
// assign to event handler and register in dictionary |
|
|
|
// assign to event handler and register in dictionary |
|
|
|
newMenuItem.Checked += OnAnyItemChecked; |
|
|
|
newMenuItem.Checked += OnAnyItemChecked; |
|
|
|
|
|
|
|
newMenuItem.Unchecked += OnAnyItemUnchecked; |
|
|
|
RegisteredSubItemsAndParent.Add(newMenuItem, sssm); |
|
|
|
RegisteredSubItemsAndParent.Add(newMenuItem, sssm); |
|
|
|
|
|
|
|
|
|
|
|
// add to parent (which is expected to be a menu item) |
|
|
|
// add to parent (which is expected to be a menu item) |
|
|
|
@ -147,6 +167,10 @@ public class SingleSelectSubMenu : MenuItem |
|
|
|
// get associated menu items |
|
|
|
// get associated menu items |
|
|
|
var associatedMenuitems = GetAssociatedMenuItems(menuItem); |
|
|
|
var associatedMenuitems = GetAssociatedMenuItems(menuItem); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get parent sssm |
|
|
|
|
|
|
|
var parentSssm = GetParentSingleSelectSubMenu(menuItem); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parentSssm.internalUncheckingOngoing = true; |
|
|
|
foreach (var associatedItem in associatedMenuitems) |
|
|
|
foreach (var associatedItem in associatedMenuitems) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// uncheck items that are not null and not the sender item |
|
|
|
// uncheck items that are not null and not the sender item |
|
|
|
@ -155,9 +179,46 @@ public class SingleSelectSubMenu : MenuItem |
|
|
|
associatedItem.IsChecked = false; |
|
|
|
associatedItem.IsChecked = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
parentSssm.internalUncheckingOngoing = false; |
|
|
|
|
|
|
|
|
|
|
|
// update SelectedMenuItem for respective parent |
|
|
|
// update SelectedMenuItem for respective parent |
|
|
|
GetParentSingleSelectSubMenu(menuItem).SelectedMenuItem = menuItem; |
|
|
|
parentSssm.SelectedMenuItem = menuItem; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Event handler that handles registered menu items being unchecked. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <param name="sender">MenuItem that was checked</param> |
|
|
|
|
|
|
|
/// <param name="e">routed event args</param> |
|
|
|
|
|
|
|
private static void OnAnyItemUnchecked(object sender, RoutedEventArgs e) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// extract sender menuItem and guard null |
|
|
|
|
|
|
|
if (sender is not MenuItem menuItem) { return; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// get parent sssm |
|
|
|
|
|
|
|
var parentSssm = GetParentSingleSelectSubMenu(menuItem); |
|
|
|
|
|
|
|
// if automated unchecking is ongoing => ignore events |
|
|
|
|
|
|
|
if (parentSssm.internalUncheckingOngoing) { return; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if unselection is not allowed => recheck |
|
|
|
|
|
|
|
if (parentSssm.AllowNoneSelected == false) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
menuItem.IsChecked = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
|
|
|
/// Event handler that handles if the property AllowNoneSelected changed. |
|
|
|
|
|
|
|
/// </summary> |
|
|
|
|
|
|
|
/// <param name="d">sender</param> |
|
|
|
|
|
|
|
/// <param name="e">routed event args</param> |
|
|
|
|
|
|
|
/// <exception cref="NotImplementedException"></exception> |
|
|
|
|
|
|
|
private static void OnAllowNoneSelectedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// extract instance and guard null |
|
|
|
|
|
|
|
// if (d is not SingleSelectSubMenu sssm) { return; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// nothing to do |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#region Helpers |
|
|
|
#region Helpers |
|
|
|
|