using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using DevExpress.Xpf.Grid;
namespace Client
{
public class AutoScrollHelper
{
public AutoScrollHelper(TableView view, int thresholdInner = 200, int thresholdOutter = 200, int horizontalScrollStep = 50)
{
if (view == null || view.Grid == null)
{
throw new ArgumentNullException("view or Grid cannot be null");
}
ThresholdInner = thresholdInner;
ThresholdOutter = thresholdOutter;
HorizontalScrollStep = horizontalScrollStep;
fGrid = view.Grid;
fView = view;
fScrollInfo = new ScrollInfo(this, view);
}
private GridControl fGrid;
private TableView fView;
private ScrollInfo fScrollInfo;
public int ThresholdInner = 200;
public int ThresholdOutter = 200;
public int HorizontalScrollStep = 50;
public int ScrollTimerInterval
{
get => (int)fScrollInfo.scrollTimer.Interval.TotalMilliseconds;
set => fScrollInfo.scrollTimer.Interval = TimeSpan.FromMilliseconds(value);
}
public void ScrollIfNeeded()
{
Point pt = Mouse.GetPosition(fView);
Rect rect = new Rect(0, 0, fView.ActualWidth, fView.ActualHeight);
fScrollInfo.GoLeft = (pt.X > rect.Left - ThresholdOutter) && (pt.X < rect.Left + ThresholdInner);
fScrollInfo.GoRight = (pt.X > rect.Right - ThresholdInner) && (pt.X < rect.Right + ThresholdOutter);
fScrollInfo.GoUp = (pt.Y < rect.Top + ThresholdInner) && (pt.Y > rect.Top - ThresholdOutter);
fScrollInfo.GoDown = (pt.Y > rect.Bottom - ThresholdInner) && (pt.Y < rect.Bottom + ThresholdOutter);
}
internal class ScrollInfo
{
internal DispatcherTimer scrollTimer;
private TableView view;
private bool left, right, up, down;
private readonly AutoScrollHelper owner;
public ScrollInfo(AutoScrollHelper owner, TableView view)
{
this.owner = owner;
this.view = view;
this.scrollTimer = new DispatcherTimer();
this.scrollTimer.Interval = TimeSpan.FromMilliseconds(100);
this.scrollTimer.Tick += ScrollTimer_Tick;
}
public bool GoLeft
{
get => left;
set
{
if (left != value)
{
left = value;
CalcInfo();
}
}
}
public bool GoRight
{
get => right;
set
{
if (right != value)
{
right = value;
CalcInfo();
}
}
}
public bool GoUp
{
get => up;
set
{
if (up != value)
{
up = value;
CalcInfo();
}
}
}
public bool GoDown
{
get => down;
set
{
if (down != value)
{
down = value;
CalcInfo();
}
}
}
private void ScrollTimer_Tick(object sender, EventArgs e)
{
owner.ScrollIfNeeded();
var scrollViewer = FindVisualChild<ScrollViewer>(owner.fGrid);
if (scrollViewer != null)
{
if (GoDown)
view.TopRowIndex++;
if (GoUp)
view.TopRowIndex--;
if (GoLeft)
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset - owner.HorizontalScrollStep);
if (GoRight)
scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + owner.HorizontalScrollStep);
}
if (!Mouse.LeftButton.HasFlag(MouseButtonState.Pressed))
scrollTimer.Stop();
}
private void CalcInfo()
{
if (!(GoDown && GoLeft && GoRight && GoUp))
scrollTimer.Stop();
if (GoDown || GoLeft || GoRight || GoUp)
scrollTimer.Start();
}
private static T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T typedChild)
{
return typedChild;
}
var childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
{
return childOfChild;
}
}
return null;
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!