初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
源码指引:github源码指引_初级代码游戏的博客-CSDN博客
C#是我多年以来的业余爱好,新搞的东西能用C#的就用C#了。
WinUI3里面有个SplitView,实现了两块面板,但是是不带鼠标拖动改变大小的功能的,其设计目标不是两块面板,而是根据需要隐藏一个面板。
一般来说,移动设备上确实不需要用户改变界面比例,但是你是WinUI3啊。所以说微软脑子里都是些什么啊,不如大家都散了算了。
因为写Winforms程序的时候我非常依赖手动调整界面比例,对于不能自主调整的完全不能忍,所以,我必须实现一个SplitPanel。
目录
一、设计SplitPanel的基本原理
二、编写xaml
三、处理鼠标事件
3.1 初始化
3.2 鼠标事件
四、效果
通过鼠标改变界面大小的功能总是涉及到这些技术:
结合以上几点,一般实现鼠标改变界面大小的实现方法是:
在WinUI3里面我们可以借助Grid来实现:
左面板 | 分隔条 | 右面板 |
分隔条用Border就可以了,宽度2-3像素,1个像素很难点击,7、8个像素又太粗壮不好看。
左面板、右面板任意。
。。。。。。
这个Grid只有一行,所以没有定义行。有三个列,分别对应左面板、分隔条、右面板。分隔条固定为3个像素,左面板和右面板为3:1分配。左面板是DataGrid,右面板是个子Grid。
左右面板都有x:Name,因为我们需要同时改变左右面板的大小。你说改变DataGrid和子Grid的大小,让总Grid自适应行不行?这种自适应的东西很诡异,我是不太放心的。
用作分隔条的Border上也有x:Name,我们设置鼠标事件都在它上面。
这段xaml中的主列表和预览区是我实际的内容,和要实现的SplitPanel功能没有任何关系。
//设置拖动手柄
border_split.PointerPressed += OnPointerPressed;
border_split.PointerReleased += OnPointerReleased;
在窗口的构造函数里增加上述代码。为什么没有设置PointerMoved事件?因为没有按下鼠标的时候处理PointerMoved是没有意义的。
private void OnPointerMoved(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
FrameworkElement? control = sender as FrameworkElement;
if (null == control) return;
try
{
foreach (var pointer in control.PointerCaptures)
{
//control.PointerCaptures.Contains(e.Pointer)是无效的,必须用PointerId来比较
if (pointer.PointerId== e.Pointer.PointerId)
{
ChangeControlSize(control, e);
}
}
}
catch (Exception ex)
{
_ = ShowMessageBox(ex.Message, "Exception");
}
}
private void OnPointerReleased(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
FrameworkElement? control = sender as FrameworkElement;
if (null == control) return;
try
{
foreach (var pointer in control.PointerCaptures)
{
//control.PointerCaptures.Contains(e.Pointer)是无效的,必须用PointerId来比较
if (pointer.PointerId == e.Pointer.PointerId)
{
control.PointerMoved -= OnPointerMoved; ;
this.Title = "PointerReleased";
control.ReleasePointerCapture(e.Pointer);
}
}
}
catch (Exception ex)
{
_ = ShowMessageBox(ex.Message, "Exception");
}
}
private void OnPointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
FrameworkElement? control = sender as FrameworkElement;
if (null == control) return;
if (!control.CapturePointer(e.Pointer))
{
this.Title = "CapturePointer error";
return;
}
control.PointerMoved += OnPointerMoved; ;
pos = e.GetCurrentPoint(control).Position.X;
this.Title = "PointerPressed " + pos.ToString() + " - " + control.ActualWidth.ToString()+ " control.PointerCaptures "+ control.PointerCaptures.Count.ToString();
}
double pos = 0;
private void ChangeControlSize(FrameworkElement? control, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
if (null == control) return;
double move = e.GetCurrentPoint(control).Position.X - pos;
if (move >= 0)
{
if (col_preview.ActualWidth - move < 0) return;
}
else
{
if (col_mainlist.ActualWidth + move < 0) return;
}
col_preview.Width = new GridLength(col_preview.ActualWidth - move);
col_mainlist.Width = new GridLength(col_mainlist.ActualWidth + move);
}
这段代码还是比较严谨的,左右面板的名字可以随意替换。唯一不太严谨的是记录鼠标初始位置的pos,一般不建议全局变量用这样简单的方式命名。
这个代码里面有一部分没有完善处理:假设了只有一个鼠标,但仍然判断了是否正在进行鼠标捕获(根据这个假设和鼠标按下才处理鼠标移动,并不需要检查是否是正在捕获的鼠标)。严谨的方式是根据鼠标ID来分别处理,设想,如果有两个鼠标同时操作会怎么样?
处理是否是正在捕获的鼠标的时候遇到了一个坑,我已经在代码里指出。并不能简单地用鼠标对象是否在集合中来判断,必须一个一个比较ID。
这段代码只处理了宽度,如果要做纵向的,稍微修改就可以了。
差不多就是这个意思了。当然,最好能把鼠标改成专门的鼠标形状。
(这里是文档结束)