using HKW.WPF.Extensions; using System.Windows; using System.Windows.Data; using System.Windows.Input; namespace HKW.WPF.Helpers; /// /// /// public static class ElementHelper { #region IsEnabled /// /// /// /// /// public static bool GetIsEnabled(FrameworkElement element) { return (bool)element.GetValue(IsEnabledProperty); } /// /// /// public static void SetIsEnabled(FrameworkElement element, bool value) { element.SetValue(IsEnabledProperty, value); } /// /// 在按下指定按键时清除选中状态 /// public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached( "IsEnabled", typeof(bool), typeof(ElementHelper), new FrameworkPropertyMetadata(default(bool), IsEnabledPropertyChangedCallback) ); private static void IsEnabledPropertyChangedCallback( DependencyObject obj, DependencyPropertyChangedEventArgs e ) { if (obj is not FrameworkElement element) return; element.IsEnabled = GetIsEnabled(element); } #endregion #region ClearFocusOnKeyDown /// /// /// /// /// public static string GetClearFocusOnKeyDown(FrameworkElement element) { return (string)element.GetValue(ClearFocusOnKeyDownProperty); } /// /// /// /// 禁止使用此方法 public static void SetClearFocusOnKeyDown(FrameworkElement element, string value) { element.SetValue(ClearFocusOnKeyDownProperty, value); } /// /// 在按下指定按键时清除选中状态 /// public static readonly DependencyProperty ClearFocusOnKeyDownProperty = DependencyProperty.RegisterAttached( "ClearFocusOnKeyDown", typeof(string), typeof(ElementHelper), new FrameworkPropertyMetadata(default(string), ClearFocusOnKeyDownPropertyChanged) ); private static void ClearFocusOnKeyDownPropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e ) { if (obj is not FrameworkElement element) return; var keyName = GetClearFocusOnKeyDown(element); if (Enum.TryParse(keyName, false, out _) is false) throw new Exception($"Unknown key {keyName}"); element.KeyDown -= Element_KeyDown; element.KeyDown += Element_KeyDown; static void Element_KeyDown(object sender, KeyEventArgs e) { if (sender is not FrameworkElement element) return; var key = (Key)Enum.Parse(typeof(Key), GetClearFocusOnKeyDown(element)); if (e.Key == key) { // 清除控件焦点 element.ClearFocus(); // 清除键盘焦点 Keyboard.ClearFocus(); } } } #endregion #region UniformMinWidthGroup /// /// /// /// /// public static string GetUniformMinWidthGroup(FrameworkElement element) { return (string)element.GetValue(UniformWidthGroupProperty); } /// /// /// public static void SetUniformMinWidthGroup(FrameworkElement element, string value) { element.SetValue(UniformWidthGroupProperty, value); } /// /// /// public static readonly DependencyProperty UniformWidthGroupProperty = DependencyProperty.RegisterAttached( "UniformMinWidthGroup", typeof(string), typeof(ElementHelper), new FrameworkPropertyMetadata(null, UniformMinWidthGroupPropertyChanged) ); /// /// (TopParent ,(GroupName, UniformMinWidthGroupInfo)) /// private readonly static Dictionary< FrameworkElement, Dictionary > _uniformMinWidthGroups = new(); private static void UniformMinWidthGroupPropertyChanged( DependencyObject obj, DependencyPropertyChangedEventArgs e ) { if (obj is not FrameworkElement element) return; var groupName = GetUniformMinWidthGroup(element); var topParent = element.FindTopParentOnVisualTree(); // 在设计器中会无法获取顶级元素, 会提示错误, 忽略即可 if (topParent is null) return; if (_uniformMinWidthGroups.TryGetValue(topParent, out var groups) is false) { topParent.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted; groups = _uniformMinWidthGroups[topParent] = new(); } if (groups.TryGetValue(groupName, out var group) is false) group = groups[groupName] = new(); group.Elements.Add(element); element.SizeChanged -= Element_SizeChanged; element.SizeChanged += Element_SizeChanged; #region TopParent static void Dispatcher_ShutdownStarted(object? sender, EventArgs e) { if (sender is not FrameworkElement element) return; _uniformMinWidthGroups.Remove(element); } #endregion #region Element static void Element_SizeChanged(object sender, SizeChangedEventArgs e) { if (sender is not FrameworkElement element) return; var groupName = GetUniformMinWidthGroup(element); var topParent = element.FindTopParentOnVisualTree(); var groups = _uniformMinWidthGroups[topParent]; var group = groups[groupName]; var maxWidthElement = group.Elements.MaxBy(i => i.ActualWidth); if (maxWidthElement is null) return; if (maxWidthElement.ActualWidth == element.ActualWidth) maxWidthElement = element; if (maxWidthElement.ActualWidth > group.MaxWidth) { // 如果当前控件最大宽度的超过历史最大宽度, 表明非最大宽度列表中的控件超过了历史最大宽度 foreach (var item in group.Elements) item.MinWidth = maxWidthElement.ActualWidth; // 将当前控件最小宽度设为0 maxWidthElement.MinWidth = 0; group.MaxWidthElements.Clear(); // 设为最大宽度的唯一控件 group.MaxWidthElements.Add(maxWidthElement); group.MaxWidth = maxWidthElement.ActualWidth; } else if (group.MaxWidthElements.Count == 1) { maxWidthElement = group.MaxWidthElements.First(); // 当最大宽度控件只有一个时, 并且当前控件宽度小于历史最大宽度时, 表明需要降低全体宽度 if (group.MaxWidth > maxWidthElement.ActualWidth) { // 最小宽度设为0以自适应宽度 foreach (var item in group.Elements) item.MinWidth = 0; // 清空最大宽度列表, 让其刷新 group.MaxWidthElements.Clear(); } } else { // 将 MaxWidth 设置为 double.MaxValue 时, 可以让首次加载时进入此处 foreach (var item in group.Elements) { // 当控件最小宽度为0(表示其为主导宽度的控件), 并且其宽度等于最大宽度, 加入最大宽度列表 if (item.MinWidth == 0 && item.ActualWidth == maxWidthElement.ActualWidth) { group.MaxWidthElements.Add(item); } else { // 如果不是, 则从最大宽度列表删除, 并设置最小宽度为当前最大宽度 group.MaxWidthElements.Remove(item); item.MinWidth = maxWidthElement.ActualWidth; } } group.MaxWidth = maxWidthElement.ActualWidth; } } #endregion } #endregion } /// /// 统一最小宽度分组信息 /// public class UniformMinWidthGroupInfo { /// /// 最后一个最大宽度 /// public double MaxWidth { get; set; } = double.MaxValue; /// /// 所有控件 /// public HashSet Elements { get; } = new(); /// /// 最大宽度的控件 /// public HashSet MaxWidthElements { get; } = new(); }