EPLAN_PROD_Plugin/Sinvo.EplanHpD.Plugin.WPFUI/Utils/ScrollSynchronizer.cs

202 lines
7.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Sinvo.EplanHpD.Plugin.WPFUI.Utils
{
public static class ScrollSynchronizer
{
// 附加属性定义
public static readonly DependencyProperty SynchronizeWithParentProperty =
DependencyProperty.RegisterAttached(
"SynchronizeWithParent",
typeof(bool),
typeof(ScrollSynchronizer),
new PropertyMetadata(false, OnSynchronizeWithParentChanged));
// 为 ListBox 添加自动寻找内部 DataGrid 的附加属性
public static readonly DependencyProperty AutoSynchronizeChildrenProperty =
DependencyProperty.RegisterAttached(
"AutoSynchronizeChildren",
typeof(bool),
typeof(ScrollSynchronizer),
new PropertyMetadata(false, OnAutoSynchronizeChildrenChanged));
// Getter 和 Setter
public static bool GetSynchronizeWithParent(DependencyObject obj)
{
return (bool)obj.GetValue(SynchronizeWithParentProperty);
}
public static void SetSynchronizeWithParent(DependencyObject obj, bool value)
{
obj.SetValue(SynchronizeWithParentProperty, value);
}
/// <summary>
/// 当属性值改变时触发
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnSynchronizeWithParentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UIElement element)
{
if ((bool)e.NewValue)
{
// 添加事件处理
element.PreviewMouseWheel += Element_PreviewMouseWheel;
}
else
{
// 移除事件处理
element.PreviewMouseWheel -= Element_PreviewMouseWheel;
}
}
}
/// <summary>
/// 处理滚动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Element_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (sender is UIElement element)
{
// 向上查找父级 ListBox
var listBox = FindParentListBox(element);
if (listBox != null)
{
// 直接获取 ListBox 的 ScrollViewer
ScrollViewer scrollViewer = GetScrollViewer(listBox);
if (scrollViewer != null)
{
// 直接控制滚动位置
if (e.Delta < 0)
{
scrollViewer.LineDown();
}
else
{
scrollViewer.LineUp();
}
// 标记事件已处理
e.Handled = true;
}
else
{
// 如果找不到 ScrollViewer回退到事件传递
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
eventArg.RoutedEvent = UIElement.MouseWheelEvent;
eventArg.Source = sender;
listBox.RaiseEvent(eventArg);
e.Handled = true;
}
}
}
}
/// <summary>
/// 添加获取 ScrollViewer 的辅助方法
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private static ScrollViewer GetScrollViewer(DependencyObject element)
{
if (element is ScrollViewer scrollViewer)
return scrollViewer;
// 尝试从控件模板中查找 ScrollViewer
ScrollViewer result = null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element) && result == null; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
result = GetScrollViewer(child); // 递归查找
}
return result;
}
/// <summary>
/// 查找父级 ListBox
/// </summary>
/// <param name="child"></param>
/// <returns></returns>
private static ListBox FindParentListBox(DependencyObject child)
{
var parent = VisualTreeHelper.GetParent(child);
while (parent != null && !(parent is ListBox))
{
parent = VisualTreeHelper.GetParent(parent);
}
return parent as ListBox;
}
public static bool GetAutoSynchronizeChildren(DependencyObject obj)
{
return (bool)obj.GetValue(AutoSynchronizeChildrenProperty);
}
public static void SetAutoSynchronizeChildren(DependencyObject obj, bool value)
{
obj.SetValue(AutoSynchronizeChildrenProperty, value);
}
private static void OnAutoSynchronizeChildrenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ListBox listBox && (bool)e.NewValue)
{
// 监听 ListBox 的 Loaded 事件
listBox.Loaded += ListBox_Loaded;
// 监听 ItemContainerGenerator 状态变化,处理动态加载的项
listBox.ItemContainerGenerator.StatusChanged += (s, args) =>
{
if (listBox.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
AttachToAllDataGrids(listBox);
}
};
}
}
private static void ListBox_Loaded(object sender, RoutedEventArgs e)
{
if (sender is ListBox listBox)
{
AttachToAllDataGrids(listBox);
}
}
private static void AttachToAllDataGrids(ListBox listBox)
{
var dataGrids = FindVisualChildren<DataGrid>(listBox);
foreach (var dataGrid in dataGrids)
{
SetSynchronizeWithParent(dataGrid, true);
}
}
/// 查找所有指定类型的可视化子元素
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
}
}