Files
aistudio-wpf-diagram/Others/Fluent.Ribbon/Fluent.Ribbon/Adorners/KeyTipAdorner.cs
2023-04-16 20:11:40 +08:00

887 lines
33 KiB
C#

#nullable enable
// ReSharper disable once CheckNamespace
namespace Fluent
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using Fluent.Extensibility;
using Fluent.Internal;
/// <summary>
/// Represents adorner for KeyTips.
/// KeyTipAdorners is chained to produce one from another.
/// Detaching root adorner couses detaching all adorners in the chain
/// </summary>
public class KeyTipAdorner : Adorner
{
#region Events
/// <summary>
/// This event is occured when adorner is
/// detached and is not able to be attached again
/// </summary>
public event EventHandler<KeyTipPressedResult>? Terminated;
#endregion
#region Fields
// KeyTips that have been
// found on this element
private readonly List<KeyTipInformation> keyTipInformations = new List<KeyTipInformation>();
private readonly FrameworkElement oneOfAssociatedElements;
// Parent adorner
private readonly KeyTipAdorner? parentAdorner;
private KeyTipAdorner? childAdorner;
private readonly FrameworkElement keyTipElementContainer;
// Is this adorner attached to the adorned element?
private bool attached;
private bool isAttaching;
// Designate that this adorner is terminated
private bool terminated;
private AdornerLayer? adornerLayer;
#endregion
#region Properties
/// <summary>
/// Determines whether at least one on the adorners in the chain is alive
/// </summary>
public bool IsAdornerChainAlive
{
get { return this.isAttaching || this.attached || this.childAdorner?.IsAdornerChainAlive == true; }
}
/// <summary>
/// Returns whether any key tips are visibile.
/// </summary>
public bool AreAnyKeyTipsVisible
{
get { return this.keyTipInformations.Any(x => x.IsVisible) || this.childAdorner?.AreAnyKeyTipsVisible == true; }
}
/// <summary>
/// Gets the currently active <see cref="KeyTipAdorner"/> by following eventually present child adorners.
/// </summary>
public KeyTipAdorner ActiveKeyTipAdorner
{
get
{
return this.childAdorner?.IsAdornerChainAlive == true
? this.childAdorner.ActiveKeyTipAdorner
: this;
}
}
/// <summary>
/// Gets a copied list of the currently available <see cref="KeyTipInformation"/>.
/// </summary>
public IReadOnlyList<KeyTipInformation> KeyTipInformations
{
get
{
return this.keyTipInformations.ToList();
}
}
#endregion
#region Intialization
/// <summary>
/// Construcotor
/// </summary>
/// <param name="adornedElement">Element to adorn.</param>
/// <param name="parentAdorner">Parent adorner or null.</param>
/// <param name="keyTipElementContainer">The element which is container for elements.</param>
public KeyTipAdorner(FrameworkElement adornedElement, FrameworkElement keyTipElementContainer, KeyTipAdorner parentAdorner)
: base(adornedElement)
{
this.parentAdorner = parentAdorner;
this.keyTipElementContainer = keyTipElementContainer;
// Try to find supported elements
this.FindKeyTips(this.keyTipElementContainer, false);
this.oneOfAssociatedElements = this.keyTipInformations.Count != 0
? this.keyTipInformations[0].AssociatedElement
: adornedElement // Maybe here is bug, coz we need keytipped item here...
;
}
// Find key tips on the given element
private void FindKeyTips(FrameworkElement container, bool hide)
{
var children = GetVisibleChildren(container);
foreach (var child in children)
{
var groupBox = child as RibbonGroupBox;
var keys = KeyTip.GetKeys(child);
if (keys is null == false
|| child is IKeyTipInformationProvider)
{
if (groupBox is null)
{
this.GenerateAndAddRegularKeyTipInformations(keys, child, hide);
// Do not search deeper in the tree
continue;
}
if (keys is null == false)
{
this.GenerateAndAddGroupBoxKeyTipInformation(hide, keys, child, groupBox);
}
}
var innerHide = hide || groupBox?.State == RibbonGroupBoxState.Collapsed;
this.FindKeyTips(child, innerHide);
}
}
private void GenerateAndAddGroupBoxKeyTipInformation(bool hide, string keys, FrameworkElement child, RibbonGroupBox groupBox)
{
var keyTipInformation = new KeyTipInformation(keys, child, hide || groupBox.State != RibbonGroupBoxState.Collapsed);
// Add to list & visual children collections
this.AddKeyTipInformationElement(keyTipInformation);
this.LogDebug("Found KeyTipped RibbonGroupBox \"{0}\" with keys \"{1}\".", keyTipInformation.AssociatedElement, keyTipInformation.Keys);
}
private void GenerateAndAddRegularKeyTipInformations(string? keys, FrameworkElement child, bool hide)
{
IEnumerable<KeyTipInformation>? informations = null;
if (child is IKeyTipInformationProvider keyTipInformationProvider)
{
informations = keyTipInformationProvider.GetKeyTipInformations(hide);
}
else if (keys is null == false)
{
informations = new[] { new KeyTipInformation(keys, child, hide) };
}
if (informations is null == false)
{
foreach (var keyTipInformation in informations)
{
// Add to list & visual children collections
this.AddKeyTipInformationElement(keyTipInformation);
this.LogDebug("Found KeyTipped element \"{0}\" with keys \"{1}\".", keyTipInformation.AssociatedElement, keyTipInformation.Keys);
}
}
}
private void AddKeyTipInformationElement(KeyTipInformation keyTipInformation)
{
this.keyTipInformations.Add(keyTipInformation);
this.AddVisualChild(keyTipInformation.KeyTip);
}
private static IList<FrameworkElement> GetVisibleChildren(FrameworkElement element)
{
var logicalChildren = LogicalTreeHelper.GetChildren(element)
.OfType<FrameworkElement>();
var children = logicalChildren;
// Always using the visual tree is very expensive, so we only search through it when we got specific control types.
// Using the visual tree here, in addition to the logical, partially fixes #244.
if (element is ContentPresenter
|| element is ContentControl)
{
children = children
.Concat(UIHelper.GetVisualChildren(element))
.OfType<FrameworkElement>();
}
else if (element is ItemsControl itemsControl)
{
children = children.Concat(UIHelper.GetAllItemContainers<FrameworkElement>(itemsControl));
}
// Don't show key tips for the selected content too early
if (element is RibbonTabControl ribbonTabControl
&& ribbonTabControl.SelectedContent is FrameworkElement selectedContent)
{
children = children.Except(new[] { selectedContent });
}
return children
.Where(x => x.Visibility == Visibility.Visible)
.Distinct()
.ToList();
}
#endregion
#region Attach & Detach
/// <summary>
/// Attaches this adorner to the adorned element
/// </summary>
public void Attach()
{
if (this.attached)
{
return;
}
this.isAttaching = true;
this.oneOfAssociatedElements.UpdateLayout();
this.LogDebug("Attach begin {0}", this.Visibility);
if (this.oneOfAssociatedElements.IsLoaded == false)
{
// Delay attaching
this.LogDebug("Delaying attach");
this.oneOfAssociatedElements.Loaded += this.OnDelayAttach;
return;
}
this.adornerLayer = GetAdornerLayer(this.oneOfAssociatedElements);
if (this.adornerLayer is null)
{
this.LogDebug("No adorner layer found");
this.isAttaching = false;
return;
}
this.FilterKeyTips(string.Empty);
// Show this adorner
this.adornerLayer.Add(this);
this.isAttaching = false;
this.attached = true;
this.LogDebug("Attach end");
}
private void OnDelayAttach(object sender, EventArgs args)
{
this.LogDebug("Delay attach (control loaded)");
this.oneOfAssociatedElements.Loaded -= this.OnDelayAttach;
this.Attach();
}
/// <summary>
/// Detaches this adorner from the adorned element
/// </summary>
public void Detach()
{
this.childAdorner?.Detach();
if (!this.attached)
{
return;
}
this.LogDebug("Detach Begin");
// Maybe adorner awaiting attaching, cancel it
this.oneOfAssociatedElements.Loaded -= this.OnDelayAttach;
// Show this adorner
this.adornerLayer?.Remove(this);
this.attached = false;
this.LogDebug("Detach End");
}
#endregion
#region Termination
/// <summary>
/// Terminate whole key tip's adorner chain
/// </summary>
public void Terminate(KeyTipPressedResult keyTipPressedResult)
{
if (this.terminated)
{
return;
}
this.terminated = true;
this.Detach();
this.parentAdorner?.Terminate(keyTipPressedResult);
this.childAdorner?.Terminate(keyTipPressedResult);
this.Terminated?.Invoke(this, keyTipPressedResult);
this.LogDebug("Termination");
}
#endregion
#region Static Methods
private static AdornerLayer? GetAdornerLayer(UIElement element)
{
var current = element;
while (true)
{
if (current is null)
{
return null;
}
var parent = (UIElement)VisualTreeHelper.GetParent(current)
?? (UIElement)LogicalTreeHelper.GetParent(current);
current = parent;
if (current is AdornerDecorator)
{
return AdornerLayer.GetAdornerLayer((UIElement)VisualTreeHelper.GetChild(current, 0));
}
}
}
private static UIElement GetTopLevelElement(UIElement element)
{
while (true)
{
var current = VisualTreeHelper.GetParent(element) as UIElement;
if (current is null)
{
return element;
}
element = current;
}
}
#endregion
#region Methods
/// <summary>
/// Back to the previous adorner.
/// </summary>
public void Back()
{
this.LogTrace("Invoking back.");
var control = this.keyTipElementContainer as IKeyTipedControl;
control?.OnKeyTipBack();
if (this.parentAdorner is null == false)
{
this.LogDebug("Back");
this.Detach();
this.parentAdorner.Attach();
}
else
{
this.Terminate(KeyTipPressedResult.Empty);
}
}
/// <summary>
/// Forwards to the elements with the given keys
/// </summary>
/// <param name="keys">Keys</param>
/// <param name="click">If true the element will be clicked</param>
/// <returns>If the element will be found the function will return true</returns>
public bool Forward(string keys, bool click)
{
this.LogTrace("Trying to forward keys \"{0}\"...", keys);
var keyTipInformation = this.TryGetKeyTipInformation(keys);
if (keyTipInformation is null)
{
this.LogTrace("Found no element for keys \"{0}\".", keys);
return false;
}
this.Forward(keys, keyTipInformation.AssociatedElement, click);
return true;
}
// Forward to the next element
private void Forward(string keys, FrameworkElement element, bool click)
{
this.LogTrace("Forwarding keys \"{0}\" to element \"{1}\".", keys, GetControlLogText(element));
this.Detach();
var keyTipPressedResult = KeyTipPressedResult.Empty;
if (click)
{
this.LogTrace("Invoking click.");
var control = element as IKeyTipedControl;
keyTipPressedResult = control?.OnKeyTipPressed() ?? KeyTipPressedResult.Empty;
}
var children = GetVisibleChildren(element);
if (children.Count == 0)
{
this.Terminate(keyTipPressedResult);
return;
}
// Panels aren't good elements to adorn. For example, trying to display KeyTips on MenuItems in SplitButton fails if using a panel.
var validChild = children.FirstOrDefault(x => x is Panel == false) ?? children[0];
this.childAdorner = ReferenceEquals(GetTopLevelElement(validChild), GetTopLevelElement(element)) == false
? new KeyTipAdorner(validChild, element, this)
: new KeyTipAdorner(element, element, this);
// Stop if no further KeyTips can be displayed.
if (this.childAdorner.keyTipInformations.Any() == false)
{
this.Terminate(keyTipPressedResult);
return;
}
this.childAdorner.Attach();
}
/// <summary>
/// Gets <see cref="KeyTipInformation"/> by keys.
/// </summary>
/// <param name="keys">The keys to look for.</param>
/// <returns>The <see cref="KeyTipInformation"/> associated with <paramref name="keys"/>.</returns>
private KeyTipInformation TryGetKeyTipInformation(string keys)
{
return this.keyTipInformations.FirstOrDefault(x => x.IsEnabled && x.Visibility == Visibility.Visible && keys.Equals(x.Keys, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// Determines if an of the keytips contained in this adorner start with <paramref name="keys"/>
/// </summary>
/// <returns><c>true</c> if any keytip start with <paramref name="keys"/>. Otherwise <c>false</c>.</returns>
public bool ContainsKeyTipStartingWith(string keys)
{
foreach (var keyTipInformation in this.keyTipInformations.Where(x => x.IsEnabled))
{
var content = keyTipInformation.Keys;
if (content.StartsWith(keys, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
// Hide / unhide keytips relative matching to entered keys
internal void FilterKeyTips(string keys)
{
this.LogDebug("FilterKeyTips with \"{0}\"", keys);
// Reset visibility if filter is empty
if (string.IsNullOrEmpty(keys))
{
foreach (var keyTipInformation in this.keyTipInformations)
{
keyTipInformation.Visibility = keyTipInformation.DefaultVisibility;
}
}
// Backup current visibility of key tips
foreach (var keyTipInformation in this.keyTipInformations)
{
keyTipInformation.BackupVisibility = keyTipInformation.Visibility;
}
// Hide / unhide keytips relative matching to entered keys
foreach (var keyTipInformation in this.keyTipInformations)
{
var content = keyTipInformation.Keys;
if (string.IsNullOrEmpty(keys))
{
keyTipInformation.Visibility = keyTipInformation.BackupVisibility;
}
else
{
keyTipInformation.Visibility = content.StartsWith(keys, StringComparison.OrdinalIgnoreCase)
? keyTipInformation.BackupVisibility
: Visibility.Collapsed;
}
}
this.LogDebug("Filtered key tips: {0}", this.keyTipInformations.Count(x => x.Visibility == Visibility.Visible));
}
#endregion
#region Layout & Visual Children
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
this.LogDebug("ArrangeOverride");
foreach (var keyTipInformation in this.keyTipInformations)
{
keyTipInformation.KeyTip.Arrange(new Rect(keyTipInformation.Position, keyTipInformation.KeyTip.DesiredSize));
}
return finalSize;
}
/// <inheritdoc />
protected override Size MeasureOverride(Size constraint)
{
this.LogDebug("MeasureOverride");
foreach (var keyTipInformation in this.keyTipInformations)
{
keyTipInformation.KeyTip.Measure(SizeConstants.Infinite);
}
this.UpdateKeyTipPositions();
var result = new Size(0, 0);
foreach (var keyTipInformation in this.keyTipInformations)
{
var cornerX = keyTipInformation.KeyTip.DesiredSize.Width + keyTipInformation.Position.X;
var cornerY = keyTipInformation.KeyTip.DesiredSize.Height + keyTipInformation.Position.Y;
if (cornerX > result.Width)
{
result.Width = cornerX;
}
if (cornerY > result.Height)
{
result.Height = cornerY;
}
}
return result;
}
private void UpdateKeyTipPositions()
{
this.LogDebug("UpdateKeyTipPositions");
if (this.keyTipInformations.Count == 0)
{
return;
}
double[]? rows = null;
var groupBox = this.oneOfAssociatedElements as RibbonGroupBox ?? UIHelper.GetParent<RibbonGroupBox>(this.oneOfAssociatedElements);
var panel = groupBox?.GetPanel();
if (panel is null == false
&& groupBox is null == false)
{
var height = groupBox.GetLayoutRoot().DesiredSize.Height;
rows = new[]
{
groupBox.GetLayoutRoot().TranslatePoint(new Point(0, 0), this.AdornedElement).Y,
groupBox.GetLayoutRoot().TranslatePoint(new Point(0, panel.DesiredSize.Height / 2.0), this.AdornedElement).Y,
groupBox.GetLayoutRoot().TranslatePoint(new Point(0, panel.DesiredSize.Height), this.AdornedElement).Y,
groupBox.GetLayoutRoot().TranslatePoint(new Point(0, height + 1), this.AdornedElement).Y
};
}
foreach (var keyTipInformation in this.keyTipInformations)
{
// Skip invisible keytips
if (keyTipInformation.Visibility != Visibility.Visible)
{
continue;
}
// Update KeyTip Visibility
var visualTargetIsVisible = keyTipInformation.VisualTarget.IsVisible;
var visualTargetInVisualTree = VisualTreeHelper.GetParent(keyTipInformation.VisualTarget) is null == false;
keyTipInformation.Visibility = visualTargetIsVisible && visualTargetInVisualTree ? Visibility.Visible : Visibility.Collapsed;
keyTipInformation.KeyTip.Margin = KeyTip.GetMargin(keyTipInformation.AssociatedElement);
if (IsWithinQuickAccessToolbar(keyTipInformation.AssociatedElement))
{
var x = (keyTipInformation.VisualTarget.DesiredSize.Width / 2.0) - (keyTipInformation.KeyTip.DesiredSize.Width / 2.0);
var y = keyTipInformation.VisualTarget.DesiredSize.Height - (keyTipInformation.KeyTip.DesiredSize.Height / 2.0);
if (KeyTip.GetAutoPlacement(keyTipInformation.AssociatedElement) == false)
{
switch (KeyTip.GetHorizontalAlignment(keyTipInformation.AssociatedElement))
{
case HorizontalAlignment.Left:
x = 0;
break;
case HorizontalAlignment.Right:
x = keyTipInformation.VisualTarget.DesiredSize.Width - keyTipInformation.KeyTip.DesiredSize.Width;
break;
}
}
keyTipInformation.Position = keyTipInformation.VisualTarget.TranslatePoint(new Point(x, y), this.AdornedElement);
}
else if (keyTipInformation.AssociatedElement.Name == "PART_DialogLauncherButton")
{
// Dialog Launcher Button Exclusive Placement
var keyTipSize = keyTipInformation.KeyTip.DesiredSize;
var elementSize = keyTipInformation.VisualTarget.RenderSize;
if (rows is null)
{
continue;
}
keyTipInformation.Position = keyTipInformation.VisualTarget.TranslatePoint(new Point(
(elementSize.Width / 2.0) - (keyTipSize.Width / 2.0),
0), this.AdornedElement);
keyTipInformation.Position = new Point(keyTipInformation.Position.X, rows[3]);
}
else if (KeyTip.GetAutoPlacement(keyTipInformation.AssociatedElement) == false)
{
var keyTipSize = keyTipInformation.KeyTip.DesiredSize;
var elementSize = keyTipInformation.VisualTarget.RenderSize;
double x = 0, y = 0;
switch (KeyTip.GetHorizontalAlignment(keyTipInformation.AssociatedElement))
{
case HorizontalAlignment.Left:
break;
case HorizontalAlignment.Right:
x = elementSize.Width - keyTipSize.Width;
break;
case HorizontalAlignment.Center:
case HorizontalAlignment.Stretch:
x = (elementSize.Width / 2.0) - (keyTipSize.Width / 2.0);
break;
}
switch (KeyTip.GetVerticalAlignment(keyTipInformation.AssociatedElement))
{
case VerticalAlignment.Top:
break;
case VerticalAlignment.Bottom:
y = elementSize.Height - keyTipSize.Height;
break;
case VerticalAlignment.Center:
case VerticalAlignment.Stretch:
y = (elementSize.Height / 2.0) - (keyTipSize.Height / 2.0);
break;
}
keyTipInformation.Position = keyTipInformation.VisualTarget.TranslatePoint(new Point(x, y), this.AdornedElement);
}
else if (keyTipInformation.AssociatedElement is InRibbonGallery gallery
&& gallery.IsCollapsed == false)
{
// InRibbonGallery Exclusive Placement
var keyTipSize = keyTipInformation.KeyTip.DesiredSize;
var elementSize = keyTipInformation.VisualTarget.RenderSize;
if (rows is null)
{
continue;
}
keyTipInformation.Position = keyTipInformation.VisualTarget.TranslatePoint(new Point(
elementSize.Width - (keyTipSize.Width / 2.0),
0), this.AdornedElement);
keyTipInformation.Position = new Point(keyTipInformation.Position.X, rows[2] - (keyTipSize.Height / 2));
}
else if (keyTipInformation.AssociatedElement is RibbonTabItem || keyTipInformation.AssociatedElement is Backstage)
{
// Ribbon Tab Item Exclusive Placement
var keyTipSize = keyTipInformation.KeyTip.DesiredSize;
var elementSize = keyTipInformation.VisualTarget.RenderSize;
keyTipInformation.Position = keyTipInformation.VisualTarget.TranslatePoint(new Point(
(elementSize.Width / 2.0) - (keyTipSize.Width / 2.0),
elementSize.Height - (keyTipSize.Height / 2.0)), this.AdornedElement);
}
else if (keyTipInformation.AssociatedElement is MenuItem)
{
// MenuItem Exclusive Placement
var elementSize = keyTipInformation.VisualTarget.DesiredSize;
keyTipInformation.Position = keyTipInformation.VisualTarget.TranslatePoint(
new Point(
(elementSize.Height / 3.0) + 2,
(elementSize.Height / 4.0) + 2), this.AdornedElement);
}
else if (keyTipInformation.AssociatedElement.Parent is BackstageTabControl)
{
// Backstage Items Exclusive Placement
var keyTipSize = keyTipInformation.KeyTip.DesiredSize;
var elementSize = keyTipInformation.VisualTarget.DesiredSize;
var parent = (UIElement)keyTipInformation.VisualTarget.Parent;
var positionInParent = keyTipInformation.VisualTarget.TranslatePoint(default, parent);
keyTipInformation.Position = parent.TranslatePoint(
new Point(
5,
positionInParent.Y + ((elementSize.Height / 2.0) - keyTipSize.Height)), this.AdornedElement);
}
else
{
if (RibbonProperties.GetSize(keyTipInformation.AssociatedElement) != RibbonControlSize.Large
|| IsTextBoxShapedControl(keyTipInformation.AssociatedElement))
{
var x = keyTipInformation.KeyTip.DesiredSize.Width / 2.0;
var y = keyTipInformation.KeyTip.DesiredSize.Height / 2.0;
var point = new Point(x, y);
var translatedPoint = keyTipInformation.VisualTarget.TranslatePoint(point, this.AdornedElement);
// Snapping to rows if it present
SnapToRowsIfPresent(rows, keyTipInformation, translatedPoint);
keyTipInformation.Position = translatedPoint;
}
else
{
var x = (keyTipInformation.VisualTarget.DesiredSize.Width / 2.0) - (keyTipInformation.KeyTip.DesiredSize.Width / 2.0);
var y = keyTipInformation.VisualTarget.DesiredSize.Height - 8;
var point = new Point(x, y);
var translatedPoint = keyTipInformation.VisualTarget.TranslatePoint(point, this.AdornedElement);
// Snapping to rows if it present
SnapToRowsIfPresent(rows, keyTipInformation, translatedPoint);
keyTipInformation.Position = translatedPoint;
}
}
}
}
private static bool IsTextBoxShapedControl(FrameworkElement element)
{
return element is Spinner || element is System.Windows.Controls.ComboBox || element is System.Windows.Controls.TextBox || element is System.Windows.Controls.CheckBox;
}
// Determines whether the element is children to RibbonToolBar
private static bool IsWithinRibbonToolbarInTwoLine(DependencyObject element)
{
var ribbonToolBar = UIHelper.GetParent<RibbonToolBar>(element);
var definition = ribbonToolBar?.GetCurrentLayoutDefinition();
if (definition is null)
{
return false;
}
if (definition.RowCount == 2
|| definition.Rows.Count == 2)
{
return true;
}
return false;
}
// Determines whether the element is children to quick access toolbar
private static bool IsWithinQuickAccessToolbar(DependencyObject element)
{
return UIHelper.GetParent<QuickAccessToolBar>(element) is null == false;
}
private static void SnapToRowsIfPresent(double[]? rows, KeyTipInformation keyTipInformation, Point translatedPoint)
{
if (rows is null)
{
return;
}
var withinRibbonToolbar = IsWithinRibbonToolbarInTwoLine(keyTipInformation.VisualTarget);
var index = 0;
var mindistance = Math.Abs(rows[0] - translatedPoint.Y);
for (var j = 1; j < rows.Length; j++)
{
if (withinRibbonToolbar && j == 1)
{
continue;
}
var distance = Math.Abs(rows[j] - translatedPoint.Y);
if (distance < mindistance)
{
mindistance = distance;
index = j;
}
}
translatedPoint.Y = rows[index] - (keyTipInformation.KeyTip.DesiredSize.Height / 2.0);
}
/// <inheritdoc />
protected override int VisualChildrenCount => this.keyTipInformations.Count;
/// <inheritdoc />
protected override Visual GetVisualChild(int index)
{
return this.keyTipInformations[index].KeyTip;
}
#endregion
#region Logging
[Conditional("DEBUG")]
private void LogDebug(string format, params object[] args)
{
var message = this.GetMessageLog(format, args);
Debug.WriteLine(message, "KeyTipAdorner");
}
[Conditional("TRACE")]
private void LogTrace(string format, params object[] args)
{
var message = this.GetMessageLog(format, args);
Trace.WriteLine(message, "KeyTipAdorner");
}
private string GetMessageLog(string format, object[] args)
{
var name = GetControlLogText(this.AdornedElement);
var message = $"[{name}] {string.Format(format, args)}";
return message;
}
private static string GetControlLogText(UIElement control)
{
var name = control.GetType().Name;
if (control is IHeaderedControl headeredControl)
{
name += $" ({headeredControl.Header})";
}
return name;
}
#endregion
}
}