C# wpf 实现任意控件(包括窗口)更多调整大小功能

WPF拖动改变大小系列

第一节 Grid内控件拖动调整大小
第二节 Canvas内控件拖动调整大小
第三节 窗口拖动调整大小
第四节 附加属性实现拖动调整大小
第五章 拓展更多调整大小功能(本章)


文章目录

  • WPF拖动改变大小系列
  • 前言
  • 一、添加的功能
    • 1、任意控件DragResize
    • 2、边界限制
    • 3、交叉拖动
      • (1)判断控件边界
      • (2)固定到控件边界
      • (3)事件转移
    • 4、拖动点模板
    • 5、拖动点容器模板
    • 6、整体模板
    • 7、窗口平滑拖动
    • 8、拖动事件
    • 9、其他功能
      • (1)适应MinWidth、MinHeight
      • (2)适应MaxWidth、MaxHeight
      • (3)适配任意dpi
  • 二、完整代码
  • 三、使用示例
    • 0、基础功能
      • (1)、引用命名空间
      • (2)、使用附加属性
    • 1、DragResize
    • 2、边界限制
    • 3、交叉拖动
    • 4、拖动点布局模板
      • (1)自定义圆点
      • (2)4个顶点
      • (3)单独定制每个点
    • 5、拖动点容器模板
      • (1)无Margin
      • (2)设置Margin
    • 6、整体模板
    • 7、窗口平滑拖动
    • 8、拖动事件
    • 9、其他功能
      • (1)适应MinWidth、MinHeight
      • (2)适应MaxWidth、MaxHeight
  • 总结


前言

上一章我们已经实现了任意控件统一的拖动调整功能,能够方便的给任意控件设置拖动调整大小。开发过程中发现还是有些功能可以继续拓展的,比如cs代码触发拖动、自定义模板、交叉拖动、限制拖动范围等功能。有功能实现起来不算太容易,却很有实用价值。


一、添加的功能

在第四章基础上添加了如下功能。

1、任意控件DragResize

我们知道wpf的Window有DragMove功能,在鼠标左键按下事件中调用此方法就能实现拖动功能很方便。对于调整大小也可以实现类似的DragResize功能, 实际效果和点击画板拖出一个形状差不多。

代码示例如下:

 /// <summary>
 /// 手动触发拖动改变大小,与Window.DragMove类似,只能在鼠标左键按下时调用。
 /// 实际效果和点击画板拖出一个形状差不多。
 /// 此方法为拓展方法,FrameworkElement的子类控件(即有宽高属性的控件)都可以调用此方法。
 /// </summary>
 /// <param name="elememt"></param>
 /// <returns>返回Task,await等待拖动完成</returns>
 /// <exception cref="InvalidOperationException"></exception>
 public static async Task DragResize(this FrameworkElement elememt)
 {
     if (Mouse.LeftButton != MouseButtonState.Pressed)
     {
         throw new InvalidOperationException("Left button down to call this method");
     }
     if (elememt.Parent == null && elememt is not Window)
     {
         throw new InvalidOperationException("Element should be on the visual tree");
     }
     //生成Resizeable对象,第四章完整代码中。
     //获取右下角Thumb
     //手动触发Thumb拖动事件
     //等待拖动完成
 }

2、边界限制

添加一个IsResizeInBounds附加属性,表示拖动范围是否在父控件内。
代码示例如下:

public static bool GetIsResizeInBounds(DependencyObject obj)
{
    return (bool)obj.GetValue(IsResizeInBoundsProperty);
}

public static void SetIsResizeInBounds(DependencyObject obj, bool value)
{
    obj.SetValue(IsResizeInBoundsProperty, value);
}

/// <summary>
/// 是否在父控件范围内拖动
/// </summary>
public static readonly DependencyProperty IsResizeInBoundsProperty =
    DependencyProperty.RegisterAttached("IsResizeInBounds", typeof(bool), typeof(Resize), new PropertyMetadata(false));

第四章的拖动逻辑中添加相应的限制功能,本质上就是判断如果超出边界则控件刚好依附在边界上,代码如下:

 var dx = left - margin.Left;
 var dy = top - margin.Top;
 if (GetIsResizeInBounds(c))
 {
     var pos = c.GetPosition();
     var parent = _resizeTarget.Parent as FrameworkElement;
     Size size;
     if (parent == null)
     {
         size.Width = SystemParameters.PrimaryScreenWidth;
         size.Height = SystemParameters.PrimaryScreenHeight;
     }
     else
     {
         size.Width = parent.ActualWidth;
         size.Height = parent.ActualHeight;
     }

     if (pos.X + dx < 0)
     {
         left = -pos.X + margin.Left;
         width = pos.X + c.ActualWidth;
     }
     else if (pos.X + dx + width > size.Width)
     {
         width = size.Width - pos.X;
         right = margin.Right + c.ActualWidth - width;
     }
     if (pos.Y + dy < 0)
     {
         top = -pos.Y + margin.Top;
         height = pos.Y + c.ActualHeight;
     }
     else if (pos.Y + dy + height > size.Height)
     {
         height = size.Height - pos.Y;
         bottom = margin.Bottom + c.ActualHeight - height;
     }
 }                

3、交叉拖动

交叉拖动是曾经用gdi画图时会出现的一种情况,gdi绘制的宽高可以为负数,所以可以直接穿过起点反向拖动也能绘制出图形。在wpf中的控件是不支持宽高负数的,所以我们需要用其他方式实现。
下列步骤以横向为例:

(1)判断控件边界

 if (width < 0

(2)固定到控件边界

SetTargetMargin为前3章的集合,根据不同控件类型比如Window是设置Left、Top、Grid则设置Margin等。minWidth是控件的MinWidth属性。margin参考第四张完整代码。

if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
//左拖动点
{
    SetTargetMargin(new Thickness(margin.Left + c.Width - minWidth, margin.Top, margin.Right - c.Width + minWidth, margin.Bottom));
}
else
//右拖动点
{
    SetTargetMargin(new Thickness(margin.Left - c.Width + minWidth, margin.Top, margin.Right + c.Width - minWidth, margin.Bottom));
}

(3)事件转移

//当前拖动点触发鼠标弹起事件
MouseButtonEventArgs upEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left)
{ RoutedEvent = UIElement.MouseLeftButtonUpEvent };
thumb.RaiseEvent(upEvent);
//反向拖动点触发鼠标按下事件
MouseButtonEventArgs downEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left)
{ RoutedEvent = UIElement.MouseLeftButtonDownEvent };
t.RaiseEvent(downEvent);

4、拖动点模板

添加附加属性ThumbsTemplate

public static ControlTemplate GetThumbsTemplate(DependencyObject obj)
{
    return (ControlTemplate)obj.GetValue(ThumbsTemplateProperty);
}

public static void SetThumbsTemplate(DependencyObject obj, ControlTemplate value)
{
    obj.SetValue(ThumbsTemplateProperty, value);
}

/// <summary>
/// 拖动点的模板
/// </summary>
public static readonly DependencyProperty ThumbsTemplateProperty =
    DependencyProperty.RegisterAttached("ThumbsTemplate", typeof(ControlTemplate), typeof(Resize), new PropertyMetadata(null));

生成拖动点时会应用模板

var thumbsTemplate = GetThumbsTemplate(_resizeTarget);
thumb.Template = thumbsTemplate;

5、拖动点容器模板

拖动点的容器模板,主要用于设置margin调整拖动点的整体位置,添加附加属性ThumbsPanel。

 public static ItemsPanelTemplate GetThumbsPanel(DependencyObject obj)
 {
     return (ItemsPanelTemplate)obj.GetValue(ThumbsPanelProperty);
 }

 public static void SetThumbsPanel(DependencyObject obj, ItemsPanelTemplate value)
 {
     obj.SetValue(ThumbsPanelProperty, value);
 }

 /// <summary>
 /// 拖动点的容器,主要用于设置margin
 /// </summary>
 public static readonly DependencyProperty ThumbsPanelProperty =
     DependencyProperty.RegisterAttached("ThumbsPanel", typeof(ItemsPanelTemplate), typeof(Resize), new PropertyMetadata(null));

生成拖动点布局时会应用模板

var itemsPanel = GetThumbsPanel(_resizeTarget);
_defalutPanel.ItemsPanel = itemsPanel;

6、整体模板

拖动点模板和拖动点布局模板已经很大程度灵活了使用,如果需要更高的定制性,直接使用整体模板,整体模板赋值后拖动点模板和拖动点布局模板会失效。此功能与第四章的ResizeTemplate相同但名称改为Template。基本规则是第一级控件为容器、第二级控件为Thumb类型自动识别为拖动点,拖动方向由HorizontalAlignment和VerticalAlignment决定。

7、窗口平滑拖动

之所有要对窗口拖动平滑处理是因为,自定义的调整大小只能设置Window的Left、Top、Width、Height,当窗口进行左或上拖动时右或下会出现残影,这种情况通过SetWindowPos和MoveWindow也无法改善。在不使用窗口自带的拖动功能的情况下,目前笔者研究出的方法就是使用透明窗口全屏,控件模拟窗口进行拖动。当然这种实现的限制就是一定要透明窗口,AllowTransparency为true或者WindowChrome的GlassFrameThickness为-1。

因为这种实现还不是很完美对装饰器不兼容,所以提供IsWindowDragSmooth属性,可以打开和关闭功能。

public static bool GetIsWindowDragSmooth(DependencyObject obj)
{
    return (bool)obj.GetValue(IsWindowDragSmoothProperty);
}

public static void SetIsWindowDragSmooth(DependencyObject obj, bool value)
{
    obj.SetValue(IsWindowDragSmoothProperty, value);
}

/// <summary>
/// 拖拽窗口调整大小是否平滑处理,作用是避免拖拽窗口左上时右下闪烁。
/// 此属性只对窗口有效
/// 此属性为true时需要透明窗口才能生效,即AllowTransparency为true或者WindowChrome的GlassFrameThickness为-1。
/// 当前版本不兼容有装饰器的窗口,拖动中装饰器可能会显示在窗口外面。
/// </summary>
// Using a DependencyProperty as the backing store for IsWindowDragSmooth.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsWindowDragSmoothProperty =
    DependencyProperty.RegisterAttached("IsWindowDragSmooth", typeof(bool), typeof(Resize), new PropertyMetadata(false));

8、拖动事件

提供3个拖动事件,拖动开始、拖动变化、拖动结束。
代码示例如下:

/// <summary>
///  拖动开始事件
/// </summary>
public static readonly RoutedEvent DragResizeStartedEvent = EventManager.RegisterRoutedEvent("DragResizeStarted", RoutingStrategy.Direct, typeof(EventHandler<DragResizeStartedEventArgs>), typeof(Resize));
/// <summary>
/// 拖动变化事件
/// </summary>
public static readonly RoutedEvent DragResizeDeltaEvent = EventManager.RegisterRoutedEvent("DragResizeDelta", RoutingStrategy.Direct, typeof(EventHandler<DragResizeDeltaEventArgs>), typeof(Resize));
/// <summary>
/// 拖动结束事件
/// </summary>
public static readonly RoutedEvent DragResizeCompletedEvent = EventManager.RegisterRoutedEvent("DragResizeCompleted", RoutingStrategy.Direct, typeof(EventHandler<DragResizeCompletedEventArgs>), typeof(Resize));

9、其他功能

(1)适应MinWidth、MinHeight

在第四章完整带的基础上将边界判断修改为控件的MinWidth、MinHeight即可。
横向

if (width >= minWidth/*原本是0*/)
{
    //略
}

纵向与横向逻辑一致,修改对应变量即可,略

(2)适应MaxWidth、MaxHeight

超过了最大值需要进行修正示例如下
横向:

if (width > c.MaxWidth)
{
    if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
    {
        left += width - c.MaxWidth;
        right = margin.Right;
    }
    else
    {
        left = margin.Left;
        right += width - c.MaxWidth;
    }
    width = c.MaxWidth;
}

纵向与横向逻辑一致,修改对应变量即可,略。

(3)适配任意dpi

所有改变坐标以及大小的代码已经适配了任意dpi。
主要注意的就是PointToScreen得到的坐标需要dpi转换。
下列是获取dpi的方法。

static Point GetDpiFromVisual(Visual visual)
{
    var source = PresentationSource.FromVisual(visual);
    var dpiX = 96.0;
    var dpiY = 96.0;
    if (source?.CompositionTarget != null)
    {
        dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
        dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
    }
    return new Point(dpiX, dpiY);
}

二、完整代码

vs2022 wpf .net 6.0 项目,包含了第四章的功能,不需要重复下载。
之后上传


三、使用示例

0、基础功能

这个是与第四章一致的基础功能。

(1)、引用命名空间

Window 的其他属性略

<Window xmlns:ac="clr-namespace:AC"/>

(2)、使用附加属性

需要某个控件可以拖动调整大小则

<Grid ac:Resize.IsResizeable="True" />

1、DragResize

DragResize需要在鼠标左键按下事件中使用,对已存在的控件或者动态生成控件使用。此方法不需要ac:Resize.IsResizeable="True"也可以使用。
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        WindowStyle="None"
        ResizeMode="NoResize"
        >
    <Grid x:Name="grid" Background="SeaGreen"  MouseLeftButtonDown="Window_MouseLeftButtonDown"/>
</Window>

因为是拓展方法,所以获取到控件对象直接调用DragResize即可。
cs

using AC;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfResize
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private async void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            //生成控件
            var border = new Border();
            border.Background = Brushes.Azure;
            border.Width = 0;
            border.Height = 0;
            //加入到容器
            grid.Children.Add(border);
            //拖出控件
            await border.DragResize();
            //如果宽高为0则移除
            if (border.Width == 0|| border.Height == 0)
            {
                grid.Children.Remove(border);
            }
        }
    }
}

效果预览
注:qq录制鼠标出现了偏移
在这里插入图片描述

2、边界限制

设置ac:Resize.IsResizeInBounds="True"即可。边界限制的范围是父控件。
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        WindowStyle="None"
        ResizeMode="NoResize"     
        >
    <Grid x:Name="grid" Background="SeaGreen">
        <Border BorderThickness="1" BorderBrush="White" Margin="40">
            <StackPanel>
                <Border ac:Resize.IsResizeable="True" ac:Resize.IsResizeInBounds="False" Background="White" Height="100" Width="200"  CornerRadius="10" >
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="不限制边界"></TextBlock>
                </Border>
                <Border ac:Resize.IsResizeable="True" ac:Resize.IsResizeInBounds="True"  Margin="0,20,0,0" Background="White" Height="100" Width="200"  CornerRadius="10" >
                    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="限制边界"></TextBlock>
                </Border>
            </StackPanel>
        </Border>
    </Grid>
</Window>

效果预览
注:qq录制鼠标出现了偏移
在这里插入图片描述

3、交叉拖动

通过附加属性ac:Resize.IsAllowsCrossover设置是否交叉拖动,默认为true。
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        WindowStyle="None"
        ResizeMode="NoResize"     
        >
    <Grid x:Name="grid" Background="SeaGreen">
        <StackPanel>
            <Border  Margin="0,20,0,0"  ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False"  Background="White" Height="100" Width="200"  CornerRadius="10" >
                <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="不允许交叉拖动"></TextBlock>
            </Border>
            <Border ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="True"   Margin="0,20,0,0" Background="White" Height="100" Width="200"  CornerRadius="10" >
                <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="允许交叉拖动"></TextBlock>
            </Border>
        </StackPanel>
    </Grid>
</Window>

效果预览
注:qq录制鼠标出现了偏移
在这里插入图片描述

4、拖动点布局模板

通过ac:Resize.ThumbsTemplate设置拖动点模板

(1)自定义圆点

xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        >
    <Grid x:Name="grid" Background="White">
        <Grid  Margin="0,20,0,0"  ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False"  Background="SeaGreen " Height="100" Width="200" >
            <ac:Resize.ThumbsTemplate>
                <ControlTemplate  >
                    <Border BorderBrush="Gray" BorderThickness="2" CornerRadius="8"  Background="White" Width="16" Height="16"/>
                </ControlTemplate>
            </ac:Resize.ThumbsTemplate>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定义拖动点模板"></TextBlock>
        </Grid>
    </Grid>
</Window>

效果预览
在这里插入图片描述

(2)4个顶点

xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        WindowStyle="None"
        ResizeMode="NoResize"
        >
    <Grid x:Name="grid" Background="White">
        <Grid  Margin="0,20,0,0"  ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False"  Background="SeaGreen " Height="100" Width="200" >
            <ac:Resize.ThumbsTemplate>
                <ControlTemplate >
                    <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8"  Background="White" Width="16" Height="16"/>
                    <!--通过触发器隐藏4条边上的点-->
                    <ControlTemplate.Triggers>
                        <!--左右两条边上的点-->
                        <Trigger Property="HorizontalAlignment" Value="Stretch">
                            <Setter TargetName="brd" Property="Visibility" Value="Collapsed" ></Setter>
                        </Trigger>
                        <!--上下两条边上的点-->
                        <Trigger Property="VerticalAlignment" Value="Stretch">
                            <Setter TargetName="brd" Property="Visibility" Value="Collapsed" ></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </ac:Resize.ThumbsTemplate>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定义拖动点模板"></TextBlock>
        </Grid>
    </Grid>
</Window>

效果预览
在这里插入图片描述

(3)单独定制每个点

通过MultiTrigger触发器来区分每个点。
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        WindowStyle="None"
        ResizeMode="NoResize"
        >
    <Grid x:Name="grid" Background="White">
        <Grid  Margin="0,20,0,0"  ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False"  Background="SeaGreen" Height="100" Width="200" >
            <ac:Resize.ThumbsTemplate>
                <ControlTemplate >
                    <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8"  Background="White" Width="16" Height="16"/>
                    <ControlTemplate.Triggers>
                         <!--左上-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Left" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Top" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="Aqua"></Setter>
                        </MultiTrigger>
                        <!--右上-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Right" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Top" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="DarkGoldenrod"></Setter>
                        </MultiTrigger>
                        <!--右下-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Right" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Bottom" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="DeepPink"></Setter>
                        </MultiTrigger>
                        <!--左下-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Left" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Bottom" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="Red"></Setter>
                        </MultiTrigger>
                        <!--上-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Stretch" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Top" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="Gold"></Setter>
                        </MultiTrigger>
                        <!--下-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Stretch" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Bottom" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="Indigo"></Setter>
                        </MultiTrigger>
                        <!--左-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Left" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Stretch" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="Blue"></Setter>
                        </MultiTrigger>
                        <!--右-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HorizontalAlignment" Value="Right" ></Condition>
                                <Condition Property="VerticalAlignment" Value="Stretch" ></Condition>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="brd" Property="BorderBrush" Value="Green"></Setter>
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </ac:Resize.ThumbsTemplate>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定义拖动点模板"></TextBlock>
        </Grid>
    </Grid>
</Window>

效果预览

在这里插入图片描述

5、拖动点容器模板

通过ac:Resize.ThumbsPanel设置拖动点容器模板,主要作用是设置margin,方便调整拖动点的偏移
默认的容器有Margin="-5"的偏移

(1)无Margin

此示例是为了说明无Margin的情况
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        WindowStyle="None"
        ResizeMode="NoResize"
        >
    <Grid x:Name="grid" Background="White">
        <Grid  Margin="0,20,0,0"  ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False"  Background="SeaGreen " Height="100" Width="200" >
            <ac:Resize.ThumbsTemplate>
                <ControlTemplate >
                    <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8"  Background="White" Width="16" Height="16"/>
                </ControlTemplate>
            </ac:Resize.ThumbsTemplate>
            <ac:Resize.ThumbsPanel>
                <ItemsPanelTemplate>
                    <Grid></Grid>
                </ItemsPanelTemplate>
            </ac:Resize.ThumbsPanel>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定义拖点容器模板"></TextBlock>
        </Grid>
    </Grid>
</Window>

效果预览
在这里插入图片描述

(2)设置Margin

Margin设置为拖动点的一半大小就刚好在边线中间。
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        WindowStyle="None"
        ResizeMode="NoResize"
        >
    <Grid x:Name="grid" Background="White">
        <Grid  Margin="0,20,0,0"  ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False"  Background="SeaGreen " Height="100" Width="200" >
            <ac:Resize.ThumbsTemplate>
                <ControlTemplate >
                    <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8"  Background="White" Width="16" Height="16"/>
                </ControlTemplate>
            </ac:Resize.ThumbsTemplate>
            <ac:Resize.ThumbsPanel>
                <ItemsPanelTemplate>
                    <Grid Margin="-8"></Grid>
                </ItemsPanelTemplate>
            </ac:Resize.ThumbsPanel>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定义拖点容器模板"></TextBlock>
        </Grid>
    </Grid>
</Window>

效果预览
在这里插入图片描述

6、整体模板

设置整体模板Template后会覆盖拖动点模板和拖动点布局模板。规则是第一级控件为容器、第二级控件为Thumb类型自动识别为拖动点,拖动方向由HorizontalAlignment和VerticalAlignment决定, 即可以有任意个拖动点Thumb,也可以放任意其他控件。

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        WindowStyle="None"
        ResizeMode="NoResize"
        >
    <Grid x:Name="grid" Background="White">
        <Grid  Margin="0,20,0,0"  ac:Resize.IsResizeable="True"   Background="SeaGreen " Height="100" Width="200" >
            <ac:Resize.Template>
                <ControlTemplate >
                    <Grid  Margin="-4">
                        <Grid.Resources>
                            <Style TargetType="Thumb">
                                <Setter Property="Width" Value="8"></Setter>
                                <Setter Property="Height" Value="8"></Setter>
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate>
                                            <Border  Background="Aqua"></Border>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </Grid.Resources>
                        <Border BorderBrush="Aqua"  BorderThickness="2" Margin="4"></Border>
                            <!--左-->
                        <Thumb   HorizontalAlignment="Left"  Cursor="SizeWE"/>
                        <!--上-->
                        <Thumb   VerticalAlignment="Top" Cursor="SizeNS"/>
                        <!--右-->
                        <Thumb   HorizontalAlignment="Right"  Cursor="SizeWE"/>
                        <!--下-->
                        <Thumb    VerticalAlignment="Bottom" Cursor="SizeNS"/>
                        <!--左上-->
                        <Thumb    HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="SizeNWSE"/>
                        <!--右上-->
                        <Thumb    HorizontalAlignment="Right" VerticalAlignment="Top"  Cursor="SizeNESW"/>
                        <!--右下-->
                        <Thumb    HorizontalAlignment="Right" VerticalAlignment="Bottom"  Cursor="SizeNWSE"/>
                        <!--左下-->
                        <Thumb    HorizontalAlignment="Left" VerticalAlignment="Bottom" Cursor="SizeNESW"/>
                    </Grid>
                </ControlTemplate>
            </ac:Resize.Template>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定义整体模板"></TextBlock>
        </Grid>
    </Grid>
</Window>

效果预览
在这里插入图片描述

7、窗口平滑拖动

窗口为透明窗口(AllowTransparency为true或者WindowChrome的GlassFrameThickness为-1),附加属性 ac:Resize.IsWindowDragSmooth设置为true即可以实现平滑拖动。
注:当前版本和装饰器不兼容,拖动时装饰器可能显示在窗口外面,谨慎使用此属性

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        WindowStyle="None"
        ResizeMode="NoResize"
        AllowsTransparency="True"
        ac:Resize.IsResizeable="True"
        ac:Resize.IsWindowDragSmooth="True"
        >
    <Grid Background="SeaGreen "/>
</Window>

作为对比先展示非平滑拖动
注:qq录制鼠标出现了偏移
在这里插入图片描述

设置平滑拖动效果预览
注:qq录制鼠标出现了偏移
在这里插入图片描述

8、拖动事件

3个事件,拖动开始ac:Resize.DragResizeStarted、拖动变化ac:Resize.DragResizeDelta、拖动结束ac:Resize.DragResizeCompleted
xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        >
    <Grid Background="SeaGreen ">
        <Border Background="Aqua" Width="200" Height="200"   ac:Resize.IsResizeable="True"  ac:Resize.DragResizeStarted="Border_DragResizeStarted"  ac:Resize.DragResizeCompleted="Border_DragResizeCompleted" ac:Resize.DragResizeDelta="Border_DragResizeDelta"></Border>
    </Grid>
</Window>

cs

using AC;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfResize
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Border_DragResizeStarted(object sender, DragResizeStartedEventArgs e)
        {
            Console.WriteLine("开始拖动");
        }

        private void Border_DragResizeCompleted(object sender, DragResizeCompletedEventArgs e)
        {
            Console.WriteLine("结束拖动");
        }

        private void Border_DragResizeDelta(object sender, DragResizeDeltaEventArgs e)
        {
            Console.WriteLine("横向变化:"+e.HorizontalChange+ " 纵向变化:"+e.VerticalChange+ " 宽变化:" + e.WidthChange + " 高变化:" + e.HeightChange);
        }
    }
}

效果预览
注:qq录制鼠标出现了偏移在这里插入图片描述

9、其他功能

(1)适应MinWidth、MinHeight

xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        >
    <Grid Background="SeaGreen ">
        <Border Background="Aqua" MinWidth="100" MinHeight="100" Width="200" Height="200"   ac:Resize.IsResizeable="True"  ></Border>
    </Grid>
</Window>

效果预览
注:qq录制鼠标出现了偏移
在这里插入图片描述

(2)适应MaxWidth、MaxHeight

xaml

<Window x:Class="WpfResize.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfResize"
        xmlns:ac="clr-namespace:AC"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"  
        >
    <Grid Background="SeaGreen ">
        <Border Background="Aqua" MaxWidth="200" MaxHeight="200" Width="100" Height="100"   ac:Resize.IsResizeable="True"  ></Border>
    </Grid>
</Window>

效果预览
在这里插入图片描述


总结

以上就是今天要讲的内容,拓展后的功能更加全面以及兼容性更强了,比如DragRezie就可以用于画板,边界限制也是比较实用的功能,拖动点模板简化了自定义的难度,拖动事件可以用于实现撤销重做功能,窗口平滑拖动优化了使用体验。但是还是有些功能不够完,需要后期继续优化。总的来说,本文实现的拖动调整大小模块已经变得更加方便实用,后期还会继续完善优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/324963.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vant2组件的使用

组件地址&#xff1a;Vant 2 - Mobile UI Components built on VueMobile UI Components built on Vuehttps://vant-contrib.gitee.io/vant/v2/#/zh-CN/ 通过 npm 安装 # Vue 3 项目&#xff0c;安装最新版 Vant&#xff1a; npm i vant -S # Vue 2 项目&#xff0c;安装 Va…

transfomer中Decoder和Encoder的base_layer的源码实现

简介 Encoder和Decoder共同组成transfomer,分别对应图中左右浅绿色框内的部分. Encoder&#xff1a; 目的&#xff1a;将输入的特征图转换为一系列自注意力的输出。 工作原理&#xff1a;首先&#xff0c;通过卷积神经网络&#xff08;CNN&#xff09;提取输入图像的特征。然…

Java集合之LinkedList源码篇

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…

自动化测试:fixture学得好,Pytest测试框架用到老

在pytest中&#xff0c;fixture是一种非常有用的特性&#xff0c;它允许我们在测试函数中注入数据或状态&#xff0c;以便进行测试。而参数化则是fixture的一个特性&#xff0c;它允许我们将不同的数据传递给fixture&#xff0c;从而进行多次测试。 本文将介绍如何在pytest中使…

任务14:使用MapReduce提取全国每年最低/最高气温

任务描述 知识点&#xff1a; 使用MapReduce提取数据 重 点&#xff1a; 开发MapReduce程序统计每年每个月的最低气温统计每年每个月的最高气温 内 容&#xff1a; 使用IDEA创建一个MapReduce项目开发MapReduce程序使用MapReduce统计每年每个月的最低气温使用MapReduce…

docker搭建SSH镜像、systemctl镜像、nginx镜像、tomcat镜像

目录 一、SSH镜像 二、systemctl镜像 三、nginx镜像 四、tomcat镜像 五、mysql镜像 一、SSH镜像 1、开启ip转发功能 vim /etc/sysctl.conf net.ipv4.ip_forward 1sysctl -psystemctl restart docker 2、 cd /opt/sshd/vim Dockerfile 3、生成镜像 4、启动容器并修改ro…

快速上手:Tomact集群配置(图文并茂)

目录 博客前言&#xff1a; 一.前期准备工作 1 .Tomcat集群架构图 2. 准备工具 二.配置集群 1.tomact配置 1.1首先解压一个tomact 1.2 解压后再准备2个tomcat 1.3修改第二个的端口号 ​编辑 1.4修改默认页面 ​编辑1.5启动8080的tomact 2.nginx 安装配置 2.1.安装…

Spring框架的背景学习

Spring 的前世今生 相信经历过不使用框架开发 Web 项目的 70 后、80 后都会有如此感触&#xff0c;如今的程序员开发项目太轻松了&#xff0c;基本只需要关心业务如何实现&#xff0c;通用技术问题只需要集成框架便可。早在 2007 年&#xff0c;一个基于 Java语言的开源框架正…

Onenote是什么?笔记软件Onenote使用指南:简介|功能|下载|替代软件

OneNote是什么&#xff1f; OneNote是微软公司开发的一款强大的笔记软件&#xff0c;它允许用户在各种设备上创建、组织和搜索笔记。OneNote以其灵活的布局和强大的编辑功能而闻名&#xff0c;它可以帮助个人和团队记录信息、规划项目、协作和分享知识。 *笔记软件OneNote On…

彝族民居一大特色——土掌房

彝族民居一大特色——土掌房在彝区&#xff0c;各地、各支系传承的居室建筑形式是多种多样的&#xff0c;并与当地的居住习俗有密切关联&#xff0c;从村寨的聚落到住宅的地址&#xff1b;从房间的分置到什物的堆放&#xff1b;从建筑结构到民居信仰和禁忌&#xff0c;都表现出…

【学习心得】图解Git命令

图解Git命令的图片是在Windows操作系统中的Git Bash里操作截图。关于Git的下载安装和理论学习大家可以先看看我写的另两篇文章。链接我放在下面啦&#xff1a; 【学习心得】Git快速上手_git学习心得-CSDN博客 【学习心得】Git深入学习-CSDN博客 一、初始化仓库 命令&#xff…

通用外设-W25Q64

前言 一、SPI通信 二、W25Q64基初时序 1.各种命令代码 2.代码 1.写使能指令 2.读取芯片是否忙碌状态并等待 3.写入数据 4.擦除函数操作 5.读取代码 三.验证 四.擦除说明 总结 前言 在单片机中一般32K FLASH就够用了&#xff0c;但是当我们使用图片或其他大量数据时…

支持华为GaussDB数据库的免费开源ERP:人力资源管理解决方案概述

开源智造所推出的Odoo SuperPeople数字化解决方案将HR和薪资数据与财务、项目规划、预算和采购流程连接起来&#xff0c;消除了多套系统给企业带来的信息孤岛问题。 ——复星集团 人力资源中心 高经理 一种更具吸引力、更有洞察力的人员管理方式 什么是开源智造Odoo的人力资源…

每日一练:LeeCode-102、二又树的层序遍历【二叉树】

本文是力扣LeeCode-102、二又树的层序遍历 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&…

【数据结构】哈希表详解,举例说明 java中的 HashMap

一、哈希表&#xff08;Hash Table&#xff09;简介&#xff1a; 哈希表是一种数据结构&#xff0c;用于实现字典或映射等抽象数据类型。它通过把关键字映射到表中的一个位置来实现快速的数据检索。哈希表的基本思想是利用哈希函数将关键字映射到数组的索引位置上&#xff0c;…

java多线程(并发)夯实之路-volatile深入浅出

volatile volatile&#xff08;易变关键字&#xff09;可以用来修饰成员变量和静态成员变量&#xff0c;线程只能从主存中获取它的值&#xff0c;线程操作volatile变量都是直接操作主存 与synchronzied区别&#xff1a;synchronzied需要创建Monitor&#xff0c;属于重量级的操…

读书笔记——《未来简史》

前言 《未来简史》是以色列历史学家尤瓦尔赫拉利的人类简史三部曲之一。三部分别为《人类简史》《未来简史》《今日简史》。其中最为著名的当然是《人类简史》&#xff0c;非常宏大的一本关于人类文明历史的书籍&#xff0c;绝对可以刷新历史观&#xff0c;《人类简史》这本书…

DAY01_Spring—Spring框架介绍IOCSpring工厂模式

目录 1 什么是框架2 Spring框架2.1 Spring介绍2.2 MVC模型说明2.3 IOC思想2.3.1 问题说明2.3.2 IOC说明 3 Spring IOC具体实现3.1 环境准备3.1.1 关于JDK说明3.1.2 检查JDK环境配置 3.2 创建项目3.3 关于Maven 命令3.3.1 install 命令3.3.2 clean 命令 3.4 添加jar包文件3.4.1 …

云计算平台建设总体技术方案详细参考

第1章. 基本情况 1.1. 项目名称 XX 公司 XX 云计算平台工程。 1.2. 业主公司 XX 公司。 1.3. 项目背景 1.3.1. XX 技术发展方向 XX&#xff0c;即运用计算机、网络和通信等现代信息技术手段&#xff0c;实现政府组织结构和工作流程的优化重组&#xff0c;超越时间、空间…

【AIGC入门一】Transformers 模型结构详解及代码解析

Transformers 开启了NLP一个新时代&#xff0c;注意力模块目前各类大模型的重要结构。作为刚入门LLM的新手&#xff0c;怎么能不感受一下这个“变形金刚的魅力”呢&#xff1f; 目录 Transformers ——Attention is all You Need 背景介绍 模型结构 位置编码 代码实现&…