chore: add ControlTokenManager.
This commit is contained in:
1 parent
f9982820a9
commit
2b35e4bdaf
8 files changed
+287
-310
No files matched your search
@@ -11,7 +11,7 @@
|
||||
Background="{DynamicResource SecondaryRegionBrush}"
|
||||
ResizeMode="CanResizeWithGrip"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
d:DesignHeight="800"
|
||||
d:DesignHeight="800"
|
||||
d:DesignWidth="1400"
|
||||
hc:Empty.ShowEmpty="True"
|
||||
Icon="/HandyControlDemo;component/Resources/Img/icon.ico">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:langs="clr-namespace:HandyControlDemo.Properties.Langs"
|
||||
xmlns:ex="clr-namespace:HandyControlDemo.Tools.Extension"
|
||||
Background="{DynamicResource RegionBrush}"
|
||||
Background="{DynamicResource RegionBrush}"
|
||||
MaxWidth="550"
|
||||
Height="600">
|
||||
<hc:TransitioningContentControl>
|
||||
@@ -45,7 +45,7 @@
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<Border Grid.Row="1" BorderThickness="1" BorderBrush="{DynamicResource BorderBrush}" Margin="0,16,0,0">
|
||||
<ScrollViewer>
|
||||
<ScrollViewer hc:ScrollViewerAttach.IsHoverResizingEnabled="False" hc:ScrollViewerAttach.AutoHide="False">
|
||||
<WrapPanel Orientation="Horizontal">
|
||||
<Border Style="{StaticResource BorderRegion}" Width="200" Height="200" Margin="10,10,32,10">
|
||||
<Border Background="{DynamicResource PrimaryBrush}">
|
||||
|
||||
@@ -13,8 +13,11 @@ namespace HandyControl.Controls;
|
||||
|
||||
public class ConfettiCannon
|
||||
{
|
||||
private static readonly ControlTokenManager<FrameworkElement> TokenManager =
|
||||
new(unregisterCallback: OnTokenUnregistered);
|
||||
|
||||
public static readonly DependencyProperty TokenProperty = DependencyProperty.RegisterAttached(
|
||||
"Token", typeof(string), typeof(ConfettiCannon), new PropertyMetadata(null, OnTokenChanged));
|
||||
"Token", typeof(string), typeof(ConfettiCannon), new PropertyMetadata(null, TokenManager.OnTokenChanged));
|
||||
|
||||
public static void SetToken(DependencyObject element, string value)
|
||||
=> element.SetValue(TokenProperty, value);
|
||||
@@ -23,7 +26,6 @@ public class ConfettiCannon
|
||||
=> (string) element.GetValue(TokenProperty);
|
||||
|
||||
private static readonly ConcurrentDictionary<string, ConfettiCannon> ConfettiCannons = new();
|
||||
private static readonly Dictionary<string, FrameworkElement> ContainerDict = new();
|
||||
private static readonly Lazy<ConfettiCannon> DefaultConfettiCannon = new(() => new ConfettiCannon(), true);
|
||||
private static readonly Random Random = new();
|
||||
|
||||
@@ -50,35 +52,8 @@ public class ConfettiCannon
|
||||
confettiCannon.StartAnimation();
|
||||
}
|
||||
|
||||
public static void Register(string token, FrameworkElement element)
|
||||
private static void OnTokenUnregistered(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ContainerDict[token] = element;
|
||||
}
|
||||
|
||||
public static void Unregister(FrameworkElement element)
|
||||
{
|
||||
if (element is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var first = ContainerDict.FirstOrDefault(item => ReferenceEquals(element, item.Value));
|
||||
Unregister(first.Key);
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ContainerDict.Remove(token);
|
||||
ConfettiCannons.TryRemove(token, out _);
|
||||
}
|
||||
|
||||
@@ -98,23 +73,6 @@ public class ConfettiCannon
|
||||
return ConfettiCannons[token];
|
||||
}
|
||||
|
||||
private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not FrameworkElement element)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.NewValue is null)
|
||||
{
|
||||
Unregister(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), element);
|
||||
}
|
||||
}
|
||||
|
||||
private static AdornerLayer GetAdornerLayer(string token)
|
||||
{
|
||||
AdornerDecorator decorator;
|
||||
@@ -125,7 +83,7 @@ public class ConfettiCannon
|
||||
}
|
||||
else
|
||||
{
|
||||
ContainerDict.TryGetValue(token, out FrameworkElement element);
|
||||
TokenManager.TryGetControl(token, out FrameworkElement element);
|
||||
decorator = element is System.Windows.Window
|
||||
? VisualHelper.GetChild<AdornerDecorator>(element)
|
||||
: VisualHelper.GetChild<ConfettiCannonContainer>(element);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
@@ -20,7 +19,7 @@ public class Dialog : ContentControl
|
||||
private Border _backElement;
|
||||
private AdornerContainer _container;
|
||||
|
||||
private static readonly Dictionary<string, FrameworkElement> ContainerDict = new();
|
||||
private static readonly ControlTokenManager<FrameworkElement> TokenManager = new();
|
||||
private static readonly Dictionary<string, Dialog> DialogDict = new();
|
||||
|
||||
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
|
||||
@@ -33,7 +32,8 @@ public class Dialog : ContentControl
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaskCanCloseProperty = DependencyProperty.RegisterAttached(
|
||||
"MaskCanClose", typeof(bool), typeof(Dialog), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
"MaskCanClose", typeof(bool), typeof(Dialog),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetMaskCanClose(DependencyObject element, bool value)
|
||||
=> element.SetValue(MaskCanCloseProperty, ValueBoxes.BooleanBox(value));
|
||||
@@ -51,22 +51,7 @@ public class Dialog : ContentControl
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TokenProperty = DependencyProperty.RegisterAttached(
|
||||
"Token", typeof(string), typeof(Dialog), new PropertyMetadata(default(string), OnTokenChanged));
|
||||
|
||||
private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is FrameworkElement element)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
Unregister(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), element);
|
||||
}
|
||||
}
|
||||
}
|
||||
"Token", typeof(string), typeof(Dialog), new PropertyMetadata(null, TokenManager.OnTokenChanged));
|
||||
|
||||
public static void SetToken(DependencyObject element, string value)
|
||||
=> element.SetValue(TokenProperty, value);
|
||||
@@ -79,45 +64,6 @@ public class Dialog : ContentControl
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
|
||||
}
|
||||
|
||||
public static void Register(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element == null) return;
|
||||
ContainerDict[token] = element;
|
||||
}
|
||||
|
||||
public static void Unregister(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element == null) return;
|
||||
|
||||
if (ContainerDict.ContainsKey(token))
|
||||
{
|
||||
if (ReferenceEquals(ContainerDict[token], element))
|
||||
{
|
||||
ContainerDict.Remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(FrameworkElement element)
|
||||
{
|
||||
if (element == null) return;
|
||||
var first = ContainerDict.FirstOrDefault(item => ReferenceEquals(element, item.Value));
|
||||
if (!string.IsNullOrEmpty(first.Key))
|
||||
{
|
||||
ContainerDict.Remove(first.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
if (ContainerDict.ContainsKey(token))
|
||||
{
|
||||
ContainerDict.Remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dialog Show<T>(string token = "") where T : new() => Show(new T(), token);
|
||||
|
||||
public static Dialog Show(object content, string token = "")
|
||||
@@ -140,10 +86,10 @@ public class Dialog : ContentControl
|
||||
{
|
||||
Close(token);
|
||||
DialogDict[token] = dialog;
|
||||
ContainerDict.TryGetValue(token, out element);
|
||||
decorator = element is System.Windows.Window ?
|
||||
VisualHelper.GetChild<AdornerDecorator>(element) :
|
||||
VisualHelper.GetChild<DialogContainer>(element);
|
||||
TokenManager.TryGetControl(token, out element);
|
||||
decorator = element is System.Windows.Window
|
||||
? VisualHelper.GetChild<AdornerDecorator>(element)
|
||||
: VisualHelper.GetChild<DialogContainer>(element);
|
||||
}
|
||||
|
||||
if (decorator != null)
|
||||
@@ -183,7 +129,7 @@ public class Dialog : ContentControl
|
||||
{
|
||||
Close(WindowHelper.GetActiveWindow());
|
||||
}
|
||||
else if (ContainerDict.TryGetValue(_token, out var element))
|
||||
else if (TokenManager.TryGetControl(_token, out var element))
|
||||
{
|
||||
Close(element);
|
||||
DialogDict.Remove(_token);
|
||||
@@ -216,6 +162,7 @@ public class Dialog : ContentControl
|
||||
{
|
||||
decorator.Child.IsEnabled = true;
|
||||
}
|
||||
|
||||
var layer = decorator.AdornerLayer;
|
||||
layer?.Remove(_container);
|
||||
IsClosed = true;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -28,6 +27,11 @@ public class Growl : Control
|
||||
private const string ElementButtonClose = "PART_ButtonClose";
|
||||
private const int MinWaitTime = 2;
|
||||
|
||||
private static GrowlWindow GrowlWindow;
|
||||
|
||||
private static readonly ControlTokenManager<Panel> TokenManager =
|
||||
new(registerCallback: OnTokenRegistered, unregisterCallback: OnTokenUnregistered);
|
||||
|
||||
public static readonly DependencyProperty GrowlParentProperty = DependencyProperty.RegisterAttached(
|
||||
"GrowlParent", typeof(bool), typeof(Growl), new PropertyMetadata(ValueBoxes.FalseBox, (o, args) =>
|
||||
{
|
||||
@@ -36,31 +40,40 @@ public class Growl : Control
|
||||
SetGrowlPanel(panel);
|
||||
}
|
||||
}));
|
||||
|
||||
public static readonly DependencyProperty ShowModeProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowMode", typeof(GrowlShowMode), typeof(Growl),
|
||||
new FrameworkPropertyMetadata(default(GrowlShowMode), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static readonly DependencyProperty ShowDateTimeProperty = DependencyProperty.Register(
|
||||
nameof(ShowDateTime), typeof(bool), typeof(Growl), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
|
||||
nameof(Message), typeof(string), typeof(Growl), new PropertyMetadata(default(string)));
|
||||
|
||||
public static readonly DependencyProperty TimeProperty = DependencyProperty.Register(
|
||||
nameof(Time), typeof(DateTime), typeof(Growl), new PropertyMetadata(default(DateTime)));
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
nameof(Icon), typeof(Geometry), typeof(Growl), new PropertyMetadata(default(Geometry)));
|
||||
|
||||
public static readonly DependencyProperty IconBrushProperty = DependencyProperty.Register(
|
||||
nameof(IconBrush), typeof(Brush), typeof(Growl), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register(
|
||||
nameof(Type), typeof(InfoType), typeof(Growl), new PropertyMetadata(default(InfoType)));
|
||||
|
||||
public static readonly DependencyProperty TokenProperty = DependencyProperty.RegisterAttached(
|
||||
"Token", typeof(string), typeof(Growl), new PropertyMetadata(default(string), OnTokenChanged));
|
||||
"Token", typeof(string), typeof(Growl), new PropertyMetadata(null, TokenManager.OnTokenChanged));
|
||||
|
||||
internal static readonly DependencyProperty CancelStrProperty = DependencyProperty.Register(
|
||||
nameof(CancelStr), typeof(string), typeof(Growl), new PropertyMetadata(default(string)));
|
||||
|
||||
internal static readonly DependencyProperty ConfirmStrProperty = DependencyProperty.Register(
|
||||
nameof(ConfirmStr), typeof(string), typeof(Growl), new PropertyMetadata(default(string)));
|
||||
|
||||
private static readonly DependencyProperty IsCreatedAutomaticallyProperty = DependencyProperty.RegisterAttached(
|
||||
"IsCreatedAutomatically", typeof(bool), typeof(Growl), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
private static GrowlWindow GrowlWindow;
|
||||
private static readonly Dictionary<string, Panel> PanelDic = new();
|
||||
|
||||
private Panel _panelMore;
|
||||
private Grid _gridMain;
|
||||
@@ -141,51 +154,15 @@ public class Growl : Control
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Confirm, ButtonOk_OnClick));
|
||||
}
|
||||
|
||||
public static void Register(string token, Panel panel)
|
||||
private static void OnTokenRegistered(string token, Panel panel)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || panel == null) return;
|
||||
PanelDic[token] = panel;
|
||||
InitGrowlPanel(panel);
|
||||
}
|
||||
|
||||
public static void Unregister(string token, Panel panel)
|
||||
private static void OnTokenUnregistered(string token, Panel panel)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || panel == null) return;
|
||||
|
||||
if (PanelDic.ContainsKey(token))
|
||||
{
|
||||
if (ReferenceEquals(PanelDic[token], panel))
|
||||
{
|
||||
PanelDic.Remove(token);
|
||||
panel.ContextMenu = null;
|
||||
panel.SetCurrentValue(PanelElement.FluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(Panel panel)
|
||||
{
|
||||
if (panel == null) return;
|
||||
var first = PanelDic.FirstOrDefault(item => ReferenceEquals(panel, item.Value));
|
||||
if (!string.IsNullOrEmpty(first.Key))
|
||||
{
|
||||
PanelDic.Remove(first.Key);
|
||||
panel.ContextMenu = null;
|
||||
panel.SetCurrentValue(PanelElement.FluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
if (PanelDic.ContainsKey(token))
|
||||
{
|
||||
var panel = PanelDic[token];
|
||||
PanelDic.Remove(token);
|
||||
panel.ContextMenu = null;
|
||||
panel.SetCurrentValue(PanelElement.FluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
}
|
||||
panel.ContextMenu = null;
|
||||
panel.SetCurrentValue(PanelElement.FluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
@@ -219,36 +196,26 @@ public class Growl : Control
|
||||
if (_panelMore == null || _gridMain == null || _buttonClose == null) throw new Exception();
|
||||
}
|
||||
|
||||
private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Panel panel)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
Unregister(panel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), panel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetToken(DependencyObject element, string value) => element.SetValue(TokenProperty, value);
|
||||
|
||||
public static string GetToken(DependencyObject element) => (string) element.GetValue(TokenProperty);
|
||||
|
||||
public static void SetShowMode(DependencyObject element, GrowlShowMode value) => element.SetValue(ShowModeProperty, value);
|
||||
public static void SetShowMode(DependencyObject element, GrowlShowMode value) =>
|
||||
element.SetValue(ShowModeProperty, value);
|
||||
|
||||
public static GrowlShowMode GetShowMode(DependencyObject element) => (GrowlShowMode) element.GetValue(ShowModeProperty);
|
||||
public static GrowlShowMode GetShowMode(DependencyObject element) =>
|
||||
(GrowlShowMode) element.GetValue(ShowModeProperty);
|
||||
|
||||
public static void SetGrowlParent(DependencyObject element, bool value) => element.SetValue(GrowlParentProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetGrowlParent(DependencyObject element, bool value) =>
|
||||
element.SetValue(GrowlParentProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetGrowlParent(DependencyObject element) => (bool) element.GetValue(GrowlParentProperty);
|
||||
|
||||
private static void SetIsCreatedAutomatically(DependencyObject element, bool value) => element.SetValue(IsCreatedAutomaticallyProperty, ValueBoxes.BooleanBox(value));
|
||||
private static void SetIsCreatedAutomatically(DependencyObject element, bool value) =>
|
||||
element.SetValue(IsCreatedAutomaticallyProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
private static bool GetIsCreatedAutomatically(DependencyObject element) => (bool) element.GetValue(IsCreatedAutomaticallyProperty);
|
||||
private static bool GetIsCreatedAutomatically(DependencyObject element) =>
|
||||
(bool) element.GetValue(IsCreatedAutomaticallyProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 开始计时器
|
||||
@@ -308,7 +275,8 @@ public class Growl : Control
|
||||
}
|
||||
};
|
||||
|
||||
PanelElement.SetFluidMoveBehavior(panel, ResourceHelper.GetResourceInternal<FluidMoveBehavior>(ResourceToken.BehaviorXY400));
|
||||
PanelElement.SetFluidMoveBehavior(panel,
|
||||
ResourceHelper.GetResourceInternal<FluidMoveBehavior>(ResourceToken.BehaviorXY400));
|
||||
}
|
||||
|
||||
private void Update()
|
||||
@@ -353,37 +321,37 @@ public class Growl : Control
|
||||
#if NET40
|
||||
new Action(
|
||||
#endif
|
||||
() =>
|
||||
() =>
|
||||
{
|
||||
if (GrowlWindow == null)
|
||||
{
|
||||
if (GrowlWindow == null)
|
||||
{
|
||||
GrowlWindow = new GrowlWindow();
|
||||
GrowlWindow.Show();
|
||||
InitGrowlPanel(GrowlWindow.GrowlPanel);
|
||||
GrowlWindow.Init();
|
||||
}
|
||||
|
||||
GrowlWindow.Show(true);
|
||||
|
||||
var ctl = new Growl
|
||||
{
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime),
|
||||
FlowDirection = growlInfo.FlowDirection
|
||||
};
|
||||
|
||||
ShowInternal(GrowlWindow.GrowlPanel, ctl);
|
||||
GrowlWindow = new GrowlWindow();
|
||||
GrowlWindow.Show();
|
||||
InitGrowlPanel(GrowlWindow.GrowlPanel);
|
||||
GrowlWindow.Init();
|
||||
}
|
||||
|
||||
GrowlWindow.Show(true);
|
||||
|
||||
var ctl = new Growl
|
||||
{
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime),
|
||||
FlowDirection = growlInfo.FlowDirection
|
||||
};
|
||||
|
||||
ShowInternal(GrowlWindow.GrowlPanel, ctl);
|
||||
}
|
||||
#if NET40
|
||||
)
|
||||
#endif
|
||||
@@ -400,38 +368,38 @@ public class Growl : Control
|
||||
#if NET40
|
||||
new Action(
|
||||
#endif
|
||||
() =>
|
||||
() =>
|
||||
{
|
||||
var ctl = new Growl
|
||||
{
|
||||
var ctl = new Growl
|
||||
{
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime)
|
||||
};
|
||||
Message = growlInfo.Message,
|
||||
Time = DateTime.Now,
|
||||
Icon = ResourceHelper.GetResource<Geometry>(growlInfo.IconKey) ?? growlInfo.Icon,
|
||||
IconBrush = ResourceHelper.GetResource<Brush>(growlInfo.IconBrushKey) ?? growlInfo.IconBrush,
|
||||
_showCloseButton = growlInfo.ShowCloseButton,
|
||||
ActionBeforeClose = growlInfo.ActionBeforeClose,
|
||||
_staysOpen = growlInfo.StaysOpen,
|
||||
ShowDateTime = growlInfo.ShowDateTime,
|
||||
ConfirmStr = growlInfo.ConfirmStr,
|
||||
CancelStr = growlInfo.CancelStr,
|
||||
Type = growlInfo.Type,
|
||||
_waitTime = Math.Max(growlInfo.WaitTime, MinWaitTime)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(growlInfo.Token))
|
||||
if (!string.IsNullOrEmpty(growlInfo.Token))
|
||||
{
|
||||
if (TokenManager.TryGetControl(growlInfo.Token, out var panel))
|
||||
{
|
||||
if (PanelDic.TryGetValue(growlInfo.Token, out var panel))
|
||||
{
|
||||
ShowInternal(panel, ctl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GrowlPanel is null, we create it automatically
|
||||
GrowlPanel ??= CreateDefaultPanel();
|
||||
ShowInternal(GrowlPanel, ctl);
|
||||
ShowInternal(panel, ctl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GrowlPanel is null, we create it automatically
|
||||
GrowlPanel ??= CreateDefaultPanel();
|
||||
ShowInternal(GrowlPanel, ctl);
|
||||
}
|
||||
}
|
||||
#if NET40
|
||||
)
|
||||
#endif
|
||||
@@ -514,6 +482,7 @@ public class Growl : Control
|
||||
growlInfo.IconKey ??= ResourceToken.SuccessGeometry;
|
||||
growlInfo.IconBrushKey ??= ResourceToken.SuccessBrush;
|
||||
}
|
||||
|
||||
break;
|
||||
case InfoType.Info:
|
||||
if (!growlInfo.IsCustom)
|
||||
@@ -526,6 +495,7 @@ public class Growl : Control
|
||||
growlInfo.IconKey ??= ResourceToken.InfoGeometry;
|
||||
growlInfo.IconBrushKey ??= ResourceToken.InfoBrush;
|
||||
}
|
||||
|
||||
break;
|
||||
case InfoType.Warning:
|
||||
if (!growlInfo.IsCustom)
|
||||
@@ -538,6 +508,7 @@ public class Growl : Control
|
||||
growlInfo.IconKey ??= ResourceToken.WarningGeometry;
|
||||
growlInfo.IconBrushKey ??= ResourceToken.WarningBrush;
|
||||
}
|
||||
|
||||
break;
|
||||
case InfoType.Error:
|
||||
if (!growlInfo.IsCustom)
|
||||
@@ -551,6 +522,7 @@ public class Growl : Control
|
||||
growlInfo.IconKey ??= ResourceToken.ErrorGeometry;
|
||||
growlInfo.IconBrushKey ??= ResourceToken.DangerBrush;
|
||||
}
|
||||
|
||||
break;
|
||||
case InfoType.Fatal:
|
||||
if (!growlInfo.IsCustom)
|
||||
@@ -565,6 +537,7 @@ public class Growl : Control
|
||||
growlInfo.IconKey ??= ResourceToken.FatalGeometry;
|
||||
growlInfo.IconBrushKey ??= ResourceToken.PrimaryTextBrush;
|
||||
}
|
||||
|
||||
break;
|
||||
case InfoType.Ask:
|
||||
growlInfo.StaysOpen = true;
|
||||
@@ -579,6 +552,7 @@ public class Growl : Control
|
||||
growlInfo.IconKey ??= ResourceToken.AskGeometry;
|
||||
growlInfo.IconBrushKey ??= ResourceToken.AccentBrush;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(infoType), infoType, null);
|
||||
@@ -844,7 +818,8 @@ public class Growl : Control
|
||||
_timerClose?.Stop();
|
||||
var transform = new TranslateTransform();
|
||||
_gridMain.RenderTransform = transform;
|
||||
var animation = AnimationHelper.CreateAnimation(FlowDirection == FlowDirection.LeftToRight ? ActualWidth : -ActualWidth);
|
||||
var animation =
|
||||
AnimationHelper.CreateAnimation(FlowDirection == FlowDirection.LeftToRight ? ActualWidth : -ActualWidth);
|
||||
animation.Completed += (s, e) =>
|
||||
{
|
||||
if (Parent is Panel panel)
|
||||
@@ -853,7 +828,7 @@ public class Growl : Control
|
||||
|
||||
if (GrowlWindow != null)
|
||||
{
|
||||
if (GrowlWindow.GrowlPanel != null && GrowlWindow.GrowlPanel.Children.Count == 0)
|
||||
if (GrowlWindow.GrowlPanel is { Children.Count: 0 })
|
||||
{
|
||||
GrowlWindow.Close();
|
||||
GrowlWindow = null;
|
||||
@@ -861,9 +836,9 @@ public class Growl : Control
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GrowlPanel != null && GrowlPanel.Children.Count == 0 && GetIsCreatedAutomatically(GrowlPanel))
|
||||
if (GrowlPanel is { Children.Count: 0 } && GetIsCreatedAutomatically(GrowlPanel))
|
||||
{
|
||||
// If the count of children is zero, we need to remove the panel, provided that the panel was created automatically
|
||||
// If the count of children is zero, we need to remove the panel, provided that the panel was created automatically
|
||||
RemoveDefaultPanel(GrowlPanel);
|
||||
GrowlPanel = null;
|
||||
}
|
||||
@@ -881,7 +856,7 @@ public class Growl : Control
|
||||
{
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
if (PanelDic.TryGetValue(token, out var panel))
|
||||
if (TokenManager.TryGetControl(token, out var panel))
|
||||
{
|
||||
Clear(panel);
|
||||
}
|
||||
|
||||
@@ -58,13 +58,16 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
|
||||
private static int NextId;
|
||||
|
||||
private static readonly Dictionary<string, NotifyIcon> NotifyIconDic = new();
|
||||
private static readonly ControlTokenManager<NotifyIcon> TokenManager = new();
|
||||
|
||||
static NotifyIcon()
|
||||
{
|
||||
VisibilityProperty.OverrideMetadata(typeof(NotifyIcon), new PropertyMetadata(ValueBoxes.VisibleBox, OnVisibilityChanged));
|
||||
DataContextProperty.OverrideMetadata(typeof(NotifyIcon), new FrameworkPropertyMetadata(DataContextPropertyChanged));
|
||||
ContextMenuProperty.OverrideMetadata(typeof(NotifyIcon), new FrameworkPropertyMetadata(ContextMenuPropertyChanged));
|
||||
VisibilityProperty.OverrideMetadata(typeof(NotifyIcon),
|
||||
new PropertyMetadata(ValueBoxes.VisibleBox, OnVisibilityChanged));
|
||||
DataContextProperty.OverrideMetadata(typeof(NotifyIcon),
|
||||
new FrameworkPropertyMetadata(DataContextPropertyChanged));
|
||||
ContextMenuProperty.OverrideMetadata(typeof(NotifyIcon),
|
||||
new FrameworkPropertyMetadata(ContextMenuPropertyChanged));
|
||||
}
|
||||
|
||||
private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
@@ -78,6 +81,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
{
|
||||
ctl.OnIconChanged();
|
||||
}
|
||||
|
||||
ctl.UpdateIcon(true);
|
||||
}
|
||||
else if (ctl._iconCurrentHandle != IntPtr.Zero)
|
||||
@@ -132,48 +136,9 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
_dispatcherTimerPos.Tick += DispatcherTimerPos_Tick;
|
||||
}
|
||||
|
||||
public static void Register(string token, NotifyIcon notifyIcon)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || notifyIcon == null) return;
|
||||
NotifyIconDic[token] = notifyIcon;
|
||||
}
|
||||
|
||||
public static void Unregister(string token, NotifyIcon notifyIcon)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || notifyIcon == null) return;
|
||||
|
||||
if (NotifyIconDic.ContainsKey(token))
|
||||
{
|
||||
if (ReferenceEquals(NotifyIconDic[token], notifyIcon))
|
||||
{
|
||||
NotifyIconDic.Remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(NotifyIcon notifyIcon)
|
||||
{
|
||||
if (notifyIcon == null) return;
|
||||
var first = NotifyIconDic.FirstOrDefault(item => ReferenceEquals(notifyIcon, item.Value));
|
||||
if (!string.IsNullOrEmpty(first.Key))
|
||||
{
|
||||
NotifyIconDic.Remove(first.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
if (NotifyIconDic.ContainsKey(token))
|
||||
{
|
||||
NotifyIconDic.Remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowBalloonTip(string title, string content, NotifyIconInfoType infoType, string token)
|
||||
{
|
||||
if (NotifyIconDic.TryGetValue(token, out var notifyIcon))
|
||||
if (TokenManager.TryGetControl(token, out var notifyIcon))
|
||||
{
|
||||
notifyIcon.ShowBalloonTip(title, content, infoType);
|
||||
}
|
||||
@@ -223,22 +188,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TokenProperty = DependencyProperty.Register(
|
||||
nameof(Token), typeof(string), typeof(NotifyIcon), new PropertyMetadata(default(string), OnTokenChanged));
|
||||
|
||||
private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is NotifyIcon notifyIcon)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
Unregister(notifyIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), notifyIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
nameof(Token), typeof(string), typeof(NotifyIcon), new PropertyMetadata(null, TokenManager.OnTokenChanged));
|
||||
|
||||
public string Token
|
||||
{
|
||||
@@ -247,7 +197,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
nameof(Text), typeof(string), typeof(NotifyIcon), new PropertyMetadata(default(string), OnTextChanged));
|
||||
nameof(Text), typeof(string), typeof(NotifyIcon), new PropertyMetadata(null, OnTextChanged));
|
||||
|
||||
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -268,7 +218,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
nameof(Icon), typeof(ImageSource), typeof(NotifyIcon), new PropertyMetadata(default(ImageSource), OnIconChanged));
|
||||
nameof(Icon), typeof(ImageSource), typeof(NotifyIcon), new PropertyMetadata(null, OnIconChanged));
|
||||
|
||||
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -298,7 +248,8 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BlinkIntervalProperty = DependencyProperty.Register(
|
||||
nameof(BlinkInterval), typeof(TimeSpan), typeof(NotifyIcon), new PropertyMetadata(TimeSpan.FromMilliseconds(500), OnBlinkIntervalChanged));
|
||||
nameof(BlinkInterval), typeof(TimeSpan), typeof(NotifyIcon),
|
||||
new PropertyMetadata(TimeSpan.FromMilliseconds(500), OnBlinkIntervalChanged));
|
||||
|
||||
private static void OnBlinkIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
@@ -331,6 +282,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
};
|
||||
ctl._dispatcherTimerBlink.Tick += ctl.DispatcherTimerBlinkTick;
|
||||
}
|
||||
|
||||
ctl._dispatcherTimerBlink.Start();
|
||||
}
|
||||
else
|
||||
@@ -419,6 +371,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
{
|
||||
hWnd = InteropMethods.FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
|
||||
}
|
||||
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
@@ -432,6 +385,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
hTrayWnd = FindTrayToolbarOverFlowWindow();
|
||||
isTrue = FindNotifyIcon(hTrayWnd, ref rectNotifyList);
|
||||
}
|
||||
|
||||
rectList = rectNotifyList;
|
||||
return isTrue;
|
||||
}
|
||||
@@ -446,8 +400,11 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
if (count > 0)
|
||||
{
|
||||
InteropMethods.GetWindowThreadProcessId(hTrayWnd, out var trayPid);
|
||||
var hProcess = InteropMethods.OpenProcess(InteropValues.ProcessAccess.VMOperation | InteropValues.ProcessAccess.VMRead | InteropValues.ProcessAccess.VMWrite, false, trayPid);
|
||||
var address = InteropMethods.VirtualAllocEx(hProcess, IntPtr.Zero, 1024, InteropValues.AllocationType.Commit, InteropValues.MemoryProtection.ReadWrite);
|
||||
var hProcess = InteropMethods.OpenProcess(
|
||||
InteropValues.ProcessAccess.VMOperation | InteropValues.ProcessAccess.VMRead |
|
||||
InteropValues.ProcessAccess.VMWrite, false, trayPid);
|
||||
var address = InteropMethods.VirtualAllocEx(hProcess, IntPtr.Zero, 1024,
|
||||
InteropValues.AllocationType.Commit, InteropValues.MemoryProtection.ReadWrite);
|
||||
|
||||
var btnData = new InteropValues.TBBUTTON();
|
||||
var trayData = new InteropValues.TRAYDATA();
|
||||
@@ -456,7 +413,8 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
InteropMethods.SendMessage(hTrayWnd, InteropValues.TB_GETBUTTON, i, address);
|
||||
var isTrue = InteropMethods.ReadProcessMemory(hProcess, address, out btnData, Marshal.SizeOf(btnData), out _);
|
||||
var isTrue =
|
||||
InteropMethods.ReadProcessMemory(hProcess, address, out btnData, Marshal.SizeOf(btnData), out _);
|
||||
if (!isTrue) continue;
|
||||
|
||||
if (btnData.dwData == IntPtr.Zero)
|
||||
@@ -464,18 +422,21 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
btnData.dwData = btnData.iString;
|
||||
}
|
||||
|
||||
InteropMethods.ReadProcessMemory(hProcess, btnData.dwData, out trayData, Marshal.SizeOf(trayData), out _);
|
||||
InteropMethods.ReadProcessMemory(hProcess, btnData.dwData, out trayData, Marshal.SizeOf(trayData),
|
||||
out _);
|
||||
InteropMethods.GetWindowThreadProcessId(trayData.hwnd, out var dwProcessId);
|
||||
|
||||
if (dwProcessId == (uint) handle)
|
||||
{
|
||||
var rect = new InteropValues.RECT();
|
||||
var lngRect = InteropMethods.VirtualAllocEx(hProcess, IntPtr.Zero, Marshal.SizeOf(typeof(Rect)), InteropValues.AllocationType.Commit, InteropValues.MemoryProtection.ReadWrite);
|
||||
var lngRect = InteropMethods.VirtualAllocEx(hProcess, IntPtr.Zero, Marshal.SizeOf(typeof(Rect)),
|
||||
InteropValues.AllocationType.Commit, InteropValues.MemoryProtection.ReadWrite);
|
||||
|
||||
InteropMethods.SendMessage(hTrayWnd, InteropValues.TB_GETITEMRECT, i, lngRect);
|
||||
InteropMethods.ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out _);
|
||||
|
||||
InteropMethods.VirtualFreeEx(hProcess, lngRect, Marshal.SizeOf(rect), InteropValues.FreeType.Decommit);
|
||||
InteropMethods.VirtualFreeEx(hProcess, lngRect, Marshal.SizeOf(rect),
|
||||
InteropValues.FreeType.Decommit);
|
||||
InteropMethods.VirtualFreeEx(hProcess, lngRect, 0, InteropValues.FreeType.Release);
|
||||
|
||||
var left = rectTray.Left + rect.Left;
|
||||
@@ -492,10 +453,12 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
isFind = true;
|
||||
}
|
||||
}
|
||||
|
||||
InteropMethods.VirtualFreeEx(hProcess, address, 0x4096, InteropValues.FreeType.Decommit);
|
||||
InteropMethods.VirtualFreeEx(hProcess, address, 0, InteropValues.FreeType.Release);
|
||||
InteropMethods.CloseHandle(hProcess);
|
||||
}
|
||||
|
||||
return isFind;
|
||||
}
|
||||
|
||||
@@ -515,6 +478,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
IconHelper.GetDefaultIconHandles(out _, out _iconHandle);
|
||||
_iconDefaultHandle = _iconHandle.CriticalGetHandle();
|
||||
}
|
||||
|
||||
_iconCurrentHandle = _iconDefaultHandle;
|
||||
}
|
||||
}
|
||||
@@ -610,6 +574,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
_dispatcherTimerPos.Interval = TimeSpan.FromMilliseconds(200);
|
||||
_dispatcherTimerPos.Start();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -638,12 +603,12 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
RoutedEvent = ClickEvent
|
||||
});
|
||||
}
|
||||
|
||||
_doubleClick = false;
|
||||
}
|
||||
|
||||
private void ShowContextMenu()
|
||||
{
|
||||
|
||||
if (ContextContent != null)
|
||||
{
|
||||
_contextContent ??= new Popup
|
||||
@@ -725,6 +690,7 @@ public class NotifyIcon : FrameworkElement, IDisposable
|
||||
{
|
||||
_dispatcherTimerBlink.Stop();
|
||||
}
|
||||
|
||||
UpdateIcon(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\GrowlShowMode.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\LinearLayout.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\RunningDirection.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ControlTokenManager`1.cs" />
|
||||
<Compile Include="..\..\Shared\HandyControl_Shared\Input\SimpleMouseBinding.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interactivity\EventToCommand.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interactivity\IEventArgsConverter.cs" />
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Tools;
|
||||
|
||||
internal class ControlTokenManager<T>(
|
||||
Action<string, T> registerCallback = null,
|
||||
Action<string, T> unregisterCallback = null
|
||||
)
|
||||
where T : FrameworkElement
|
||||
{
|
||||
private static readonly Dictionary<string, WeakReference<T>> ControlDict = new();
|
||||
|
||||
public void Register(string token, T control)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || control == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ControlDict[token] = new WeakReference<T>(control);
|
||||
registerCallback?.Invoke(token, control);
|
||||
}
|
||||
|
||||
public void Unregister(string token, T control)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || control == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ControlDict.TryGetValue(token, out var reference))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reference.TryGetTarget(out var target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ReferenceEquals(target, control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ControlDict.Remove(token);
|
||||
unregisterCallback?.Invoke(token, control);
|
||||
}
|
||||
|
||||
public void Unregister(T control)
|
||||
{
|
||||
if (control == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string unregisteredToken = null;
|
||||
foreach (var item in ControlDict)
|
||||
{
|
||||
if (!item.Value.TryGetTarget(out var target) || !ReferenceEquals(control, target))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
unregisteredToken = item.Key;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unregisteredToken == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ControlDict.Remove(unregisteredToken);
|
||||
unregisterCallback?.Invoke(unregisteredToken, control);
|
||||
}
|
||||
|
||||
public void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ControlDict.TryGetValue(token, out var reference))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ControlDict.Remove(token);
|
||||
|
||||
if (!reference.TryGetTarget(out var target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unregisterCallback?.Invoke(token, target);
|
||||
}
|
||||
|
||||
public bool TryGetControl(string token, out T control)
|
||||
{
|
||||
control = null;
|
||||
|
||||
if (string.IsNullOrEmpty(token) || !ControlDict.TryGetValue(token, out var reference))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return reference.TryGetTarget(out control);
|
||||
}
|
||||
|
||||
public void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not T control)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
Unregister(control);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), control);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user