You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP Grid Splitter 拖动时始终贴合鼠标位置的问题咨询

GridSplitter 拖动时光标位置未固定绑定的问题解决

我明白你遇到的这个问题——当GridSplitter拖到边界停下后,再往回拖动时,控件会跟着移动但光标并没有始终停在Splitter上,这是因为默认的拖动逻辑是基于鼠标的相对移动量,而不是跟踪绝对位置导致的。

要实现拖动过程中光标始终位于GridSplitter上的效果,我们可以自定义一个继承自GridSplitter的控件,修改其拖动逻辑为基于鼠标绝对位置计算目标列宽,同时处理边界限制后的基准值更新:

using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace YourNamespace
{
    public class FixedPositionGridSplitter : GridSplitter
    {
        private double _initialMouseX;
        private double _initialTargetColumnWidth;
        private ColumnDefinition _targetColumn;

        protected override void OnPointerPressed(PointerRoutedEventArgs e)
        {
            base.OnPointerPressed(e);
            var pointerPoint = e.GetCurrentPoint(this);
            _initialMouseX = pointerPoint.Position.X;

            // 根据你的布局,获取要调整的左侧列
            if (Parent is Grid parentGrid && Grid.Column == 1)
            {
                _targetColumn = parentGrid.ColumnDefinitions[0];
                _initialTargetColumnWidth = _targetColumn.ActualWidth;
            }

            CapturePointer(e.Pointer);
        }

        protected override void OnPointerMoved(PointerRoutedEventArgs e)
        {
            if (_targetColumn == null)
            {
                base.OnPointerMoved(e);
                return;
            }

            var pointerPoint = e.GetCurrentPoint(this);
            var mouseDeltaX = pointerPoint.Position.X - _initialMouseX;
            var newColumnWidth = _initialTargetColumnWidth + mouseDeltaX;

            // 应用最小宽度限制,同时更新基准值避免反向拖动偏移
            if (newColumnWidth >= _targetColumn.MinWidth)
            {
                _targetColumn.Width = new GridLength(newColumnWidth);
            }
            else
            {
                _targetColumn.Width = new GridLength(_targetColumn.MinWidth);
                _initialMouseX = pointerPoint.Position.X;
                _initialTargetColumnWidth = _targetColumn.MinWidth;
            }
        }

        protected override void OnPointerReleased(PointerRoutedEventArgs e)
        {
            base.OnPointerReleased(e);
            ReleasePointerCapture(e.Pointer);
            _targetColumn = null;
        }
    }
}

之后在XAML中引用这个自定义控件(记得替换YourNamespace为你的实际命名空间):

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="39"></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="100"></ColumnDefinition>
        <ColumnDefinition Width="2"></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <local:FixedPositionGridSplitter 
        Grid.Column="1" 
        Grid.Row="0" 
        Grid.RowSpan="2" 
        Width="2" 
        ResizeBehavior="BasedOnAlignment" 
        ResizeDirection="Auto" />
</Grid>

这个方案的核心是:在指针按下时记录初始的鼠标位置和目标列宽度,拖动过程中根据鼠标的绝对位置变化计算新列宽;当到达最小宽度边界时,更新初始基准值,这样反向拖动时光标就能重新和GridSplitter绑定,始终保持在控件上。

内容的提问来源于stack exchange,提问作者tscpp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:27:32