行业网站制作,微信网站建设费记什么科目,网站上传权限问题,钢筋网片验收规范及标准系列文章目录
第一章 Grid内控件拖动 第二章 Canvas内控件拖动 第三章 任意控件拖动 第四章 窗口拖动 第五章 附加属性实现任意拖动 第六章 拓展更多拖动功能#xff08;本章#xff09; 文章目录 系列文章目录前言一、添加的功能1、任意控件MoveTo2、任意控件DragMove3、边…系列文章目录
第一章 Grid内控件拖动 第二章 Canvas内控件拖动 第三章 任意控件拖动 第四章 窗口拖动 第五章 附加属性实现任意拖动 第六章 拓展更多拖动功能本章 文章目录 系列文章目录前言一、添加的功能1、任意控件MoveTo2、任意控件DragMove3、边界限制4、窗口最大化拖动还原5、拖动事件 二、完整代码三、使用示例1、MoveTo2、DragMove3、边界限制4、窗口最大化拖动还原5、拖动事件 总结 前言
上一章我们以及实现了任意控件统一的拖动功能以及能够方便的给任意控件添加拖动了。开发过程中发现还是有些功能可以继续拓展的比如cs代码中移动控件、响应事件后触发拖动、限制拖动范围等功能。 一、添加的功能
在第五章基础上添加了如下功能。
1、任意控件MoveTo
这个功能相对简单对不同类型的容器进行判断区分不同的移动逻辑即可。 代码示例如下
/// summary
/// 任意控件移动到指定坐标点
/// /summary
/// param nameelememtthis/param
/// param nameparentPoint父容器的坐标点之所以采样容器的坐标是因为采样自身坐标控件位置改变后就会无效采样屏幕坐标则需要自己换算dpiPointToScreen不会做dpi换算/param
public static void MoveTo(this FrameworkElement elememt, Point parentPoint)
{var parent VisualTreeHelper.GetParent(elememt);if (parent is Canvas){//Canvas移动逻辑}else if (elememt is Window){//Window移动逻辑}else{//Grid或Transform移动逻辑两种都能适用任意控件}
}在拓展一个获取位置的方法方便MoveTo使用
/// summary
/// 获取控件坐标基于父控件。Window则是桌面位置。
/// /summary
/// param nameelememt/param
public static Point GetPosition(this FrameworkElement elememt)
{var parent VisualTreeHelper.GetParent(elememt);if (elememt is Window){var window elememt as Window;return new Point(window!.Left, window.Top);}return elememt.TranslatePoint(new Point(0, 0), parent as UIElement);
}2、任意控件DragMove
我们知道wpf的Window有DragMove功能在鼠标左键按下事件中调用此方法就能实现拖动功能很方便。任意控件的DragMove也是可以实现的我们需要使用第五章的DragMoveable对象结合手动触发事件来实现。 代码示例如下
/// summary
/// 点击拖动
/// 与Window的DragMove类似必须鼠标左键按下调用此方法。
/// await 可以等待拖动结束
/// /summary
/// param nameelememtthis/param
/// returns/returns
/// exception crefInvalidOperationException/exception
public static Task DragMove(this FrameworkElement elememt)
{if (Mouse.LeftButton ! MouseButtonState.Pressed){throw new InvalidOperationException(Left button down to call this method);}var tcs new TaskCompletionSource();//初始化DragMoveable对象//手动触发elememt的鼠标左键按下事件//拖动完成后tcs.SetResult(); return tcs.Task;
}3、边界限制
添加一个IsMoveInBounds附加属性表示拖动范围是否在父控件内。 代码示例如下 public static bool GetIsMoveInBounds(DependencyObject obj){return (bool)obj.GetValue(IsMoveInBoundsProperty);}public static void SetIsMoveInBounds(DependencyObject obj, bool value){obj.SetValue(IsMoveInBoundsProperty, value);}/// summary/// 是否在父容器区域内拖动不会超出边界/// /summary// Using a DependencyProperty as the backing store for IsMoveInBounds. This enables animation, styling, binding, etc...public static readonly DependencyProperty IsMoveInBoundsProperty DependencyProperty.RegisterAttached(IsMoveInBounds, typeof(bool), typeof(Move), new PropertyMetadata(true));在第五章 附加属性实现任意拖动的拖动逻辑中添加相应的限制功能比如Canvas的示例如下:
var p _parent as Canvas;
if (GetIsMoveInBounds(c))
//修正移动范围
{if (left 0) left 0;if (top 0) top 0;if (left c.ActualWidth p.ActualWidth) left p.ActualWidth - c.ActualWidth;if (top c.ActualHeight p.ActualHeight) top p.ActualHeight - c.ActualHeight;
} 4、窗口最大化拖动还原
Windows系统的窗口最大化拖动标题时会自动恢复为普通状态的窗口实现无边框窗口后则失去了这个功能需要自己实现而且恢复普通状态的窗口的位置还有一定的逻辑。 代码示例如下
if (window.WindowState WindowState.Maximized)
//最大化时拖动逻辑
{ //恢复为普通窗口window.WindowState WindowState.Normal;double width SystemParameters.PrimaryScreenWidth;//得到屏幕整体宽度double height SystemParameters.PrimaryScreenHeight;//得到屏幕整体高度//根据鼠标的位置调整窗口位置基本逻辑是横向为鼠标为中点纵向为鼠标顶部,超出屏幕范围则修正到靠近的那一边。
}5、拖动事件
提供3个拖动事件拖动结束、拖动变化、拖动结束。 代码示例如下 /// summary/// 拖动开始事件/// /summarypublic static readonly RoutedEvent DragMoveStartedEvent EventManager.RegisterRoutedEvent(DragMoveStarted, RoutingStrategy.Direct, typeof(EventHandlerDragMoveStartedEventArgs), typeof(Move));
/// summary
/// 拖动变化事件
/// /summary
public static readonly RoutedEvent DragMoveDeltaEvent EventManager.RegisterRoutedEvent(DragMoveDelta, RoutingStrategy.Direct, typeof(EventHandlerDragMoveDeltaEventArgs), typeof(Move));
/// summary
/// 拖动结束事件
/// /summary
public static readonly RoutedEvent DragMoveCompletedEvent EventManager.RegisterRoutedEvent(DragMoveCompleted, RoutingStrategy.Direct, typeof(EventHandlerDragMoveCompletedEventArgs), typeof(Move));二、完整代码
vs2022 wpf .net 6.0 项目包含了第五章的功能不需要重复下载。 https://download.csdn.net/download/u013113678/88513646 三、使用示例
由于本章是第五章的拓展基本功能可以参考第五章。
1、MoveTo
xaml
Window x:ClassWpfMove.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:WpfMovemc:IgnorabledTitleMainWindow Height450 Width800GridButton Width180 Height30 ClickButton_ClickGird中点击按钮右移10/ButtonStackPanelButton Width180 Height30 ClickButton_ClickStackPanel中点击按钮右移10/Button/StackPanelCanvasButton Width180 Height30 ClickButton_ClickCanvas中点击按钮右移10/Button/Canvas/Grid
/Window因为是拓展方法所以获取到控件对象直接调用moveTo即可。 cs
using AC;
using System.Windows;
using System.Windows.Media;namespace WpfMove
{/// summary/// Interaction logic for MainWindow.xaml/// /summarypublic partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){var fe sender as FrameworkElement;//获取控件的位置var p fe.GetPosition();//右偏移10p.Offset(10, 0);fe.MoveTo(p);}}
}效果预览
2、DragMove
xaml
Window x:ClassWpfMove.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:WpfMovemc:IgnorabledTitleMainWindow Height450 Width800GridTextBlock BackgroundAqua TextAlignmentCenter Margin0,80,0,0 Width180 Height30 MouseDownTextBlock_MouseDown Gird中点击拖动/TextBlockStackPanelTextBlock BackgroundAqua TextAlignmentCenter Margin0,80,0,0 Width180 Height30 MouseDownTextBlock_MouseDown StackPanel中点击拖动/TextBlock/StackPanelCanvas TextBlock BackgroundAqua TextAlignmentCenter Margin0,80,0,0 Width180 Height30 MouseDownTextBlock_MouseDown Canvas中点击拖动/TextBlock/Canvas/Grid
/Window此方法也是拓展方法在鼠标按下事件中任意控件都可以调用此方法可以通过await等待拖动完成。 cs
using AC;
using System;
using System.Windows;namespace WpfMove
{/// summary/// Interaction logic for MainWindow.xaml/// /summarypublic partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private async void TextBlock_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e){var fe sender as FrameworkElement;await fe.DragMove();Console.WriteLine(拖动完成);}}
}效果预览
3、边界限制
通过附加属性IsMoveInBounds设置是否限制边界默认为false。 xaml
Window x:ClassWpfMove.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:WpfMovexmlns:acclr-namespace:ACmc:IgnorabledTitleMainWindow Height450 Width800GridTextBlock HorizontalAlignmentLeft BackgroundAqua TextAlignmentCenter Margin0,80,0,0 Width180 Height60 ac:Move.IsDragMoveableTrue ac:Move.IsMoveInBoundsTrue拖动限制边界/TextBlockTextBlock HorizontalAlignmentRight BackgroundAqua TextAlignmentCenter Margin0,80,0,0 Width180 Height60 ac:Move.IsDragMoveableTrue ac:Move.IsMoveInBoundsFalse拖动不限制边界/TextBlock/Grid
/Window效果预览
4、窗口最大化拖动还原
内部实现已支持最大化拖动还原只需要设置窗口可拖动即可使用场景是无边框窗口自定义标题栏。 xaml
Window x:ClassWpfMove.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:WpfMovexmlns:acclr-namespace:ACmc:IgnorabledWindowStyleNoneResizeModeNoResizeWindowStateNormalTitleMainWindow Height450 Width800x:NamewindowGridBorder VerticalAlignmentTop Height40 Background#333333 ac:Move.DragMoveTarget{Binding ElementName window} MouseLeftButtonDownBorder_MouseLeftButtonDownTextBlock Margin0,0,10,0 VerticalAlignmentCenter HorizontalAlignmentRight ForegroundWhite Text标题栏拖动窗口/TextBlock/Border/Grid
/Windowcs
using System.Windows;
namespace WpfMove
{/// summary/// Interaction logic for MainWindow.xaml/// /summarypublic partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Border_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e){if (e.ClickCount 2) WindowState WindowState ! WindowState.Maximized ? WindowState WindowState.Maximized : WindowState WindowState.Normal;}}
}效果预览
5、拖动事件
xaml
Window x:ClassWpfMove.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:WpfMovexmlns:acclr-namespace:ACmc:IgnorabledTitleMainWindow Height450 Width800StackPanelTextBlock BackgroundAqua TextAlignmentCenterMargin0,80,0,0 Width180 Height30 ac:Move.IsDragMoveableTrue ac:Move.DragMoveStartedwindow_DragMoveStartedac:Move.DragMoveCompletedwindow_DragMoveCompletedac:Move.DragMoveDeltawindow_DragMoveDeltaStackPanel中点击拖动/TextBlock/StackPanel
/Windowcs
using AC;
using System;
using System.Windows;namespace WpfMove
{/// summary/// Interaction logic for MainWindow.xaml/// /summarypublic partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void window_DragMoveStarted(object sender, DragMoveStartedEventArgs e){Console.WriteLine(拖动开始);}private void window_DragMoveCompleted(object sender, DragMoveCompletedEventArgs e){Console.WriteLine(拖动完成);}private void window_DragMoveDelta(object sender, DragMoveDeltaEventArgs e){Console.WriteLine(横向偏移e.HorizontalOffset , 纵向偏移 e.VerticalOffset);}}
}
效果预览总结
以上就是今天要讲的内容拓展更多的拖动功能后使用变得更加方便了灵活度也提高了。使用xmal或cs代码都能实现拖动实现自定义标题栏也变得很简单有了拖动事件也可以做一些撤销重做的功能。总的来说本文的拖动功能一定程度可以作为通用的模块在项目中使用了。