当前位置: 首页 > news >正文

WPF实现组件拖动(Canvas)

xaml:

<Window x:Class="WpfApp3Test.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:WpfApp3Test"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">

<Window.Resources>
<!-- 标题栏样式(针对Border类型) -->
<Style x:Key="BorderStyle" TargetType="Border">
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="YellowGreen"/>
</Style>

<!-- TextBlock样式(针对TextBlock类型) -->
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="Yellow"/>
<Setter Property="FontSize" Value="20"/>

</Style>
</Window.Resources>

 

<Grid x:Name="parentGrid" >
<Canvas x:Name="parentCanvas">
<!-- 组件A:Canvas(下层,ZIndex=1) -->
<Canvas x:Name="ComponentA" Panel.ZIndex="1" MouseLeftButtonDown="A_MouseLeftButtonDown">
<!-- Canvas内可放置绘制元素(示例:简单矩形) -->
<Rectangle Width="500" Height="300" Fill="LightBlue" />
<TextBlock Canvas.Left="20" Canvas.Top="20" Text="组件A(Canvas)" FontSize="16" />
</Canvas>

<!-- 组件B:Border(上层,ZIndex=2) -->
<Border x:Name="ComponentB"
Width="300" Height="250"
BorderBrush="Black" BorderThickness="1"
Canvas.Left="0" Canvas.Top="0"
Panel.ZIndex="2">
<!-- 层级高于A -->

<!-- B的内部布局:两行Grid -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<!-- 标题栏行(固定高度) -->
<RowDefinition Height="*" />
<!-- 内容区行(占剩余高度) -->
</Grid.RowDefinitions>

<!-- 标题栏(第一行) -->
<Border x:Name="TitleBar"
Grid.Row="0"
Style="{StaticResource BorderStyle}"
MouseLeftButtonDown="B_TitleBar_MouseLeftButtonDown" MouseMove="B_TitleBar_MouseMove">
<TextBlock Text="B的标题栏" Style="{StaticResource TextBlockStyle}" VerticalAlignment="Center" Margin="5" />
</Border>

<!-- 内容区(第二行):ScrollViewer + ItemsControl -->
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto" IsHitTestVisible="False">
<!-- 内容超出时显示滚动条 -->
<ItemsControl x:Name="ContentItems">
<!-- 列表项模板(简单文本展示) -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- 每个列表项显示文本(绑定示例) -->
<TextBlock Text="{Binding}" Margin="5" FontSize="14" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Border>
</Canvas>
</Grid>
</Window>

 

xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp3Test
{
/// <summary>
///
/// /// MainWindow.xaml 的交互逻辑
/// /// </summary>
public partial class MainWindow : Window
{
private bool _isDragging = false;

// 是否正在拖拽
private Point _lastMousePosition;

// 上一次鼠标位置(关键:每次移动后更新,避免偏移叠加)
private Point _lastTitleBarPosition;

// 存储ComponentB相对于parentCanvas的位置
public MainWindow()
{
InitializeComponent();
ContentItems.ItemsSource = new List<string> { "项1", "项2", "项3" };
}

private void A_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ MessageBox.Show("点击了组件A"); }

private void B_TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!_isDragging)
{
// 1. 启动拖拽:记录初始状态
_isDragging = true;
_lastMousePosition = e.GetPosition(parentCanvas);
//记录鼠标当前位置(相对于父Canvas)
_lastTitleBarPosition = new Point(
Canvas.GetLeft(ComponentB),
Canvas.GetTop(ComponentB)

);
TitleBar.CaptureMouse(); // 捕获鼠标,确保移动时事件不丢失
}
else
{
//2. 停止拖拽:重置状态 _
_isDragging = false;
// 释放鼠标捕获
TitleBar.ReleaseMouseCapture();
}
e.Handled = true;
// 阻止事件传递到组件A
}

private void B_TitleBar_MouseMove(object sender, MouseEventArgs e)
{
if (_isDragging && TitleBar.IsMouseCaptured)
{
// 1. 获取当前鼠标相对于parentCanvas的位置
Point currentMousePos = e.GetPosition(parentCanvas);
// 2. 计算本次移动的偏移量(当前 - 上一次鼠标位置)
double offsetX = currentMousePos.X - _lastMousePosition.X;
double offsetY = currentMousePos.Y - _lastMousePosition.Y;
// 3. 更新ComponentB的位置(基于Canvas的Left/Top)
double newLeft = _lastTitleBarPosition.X + offsetX;
double newTop = _lastTitleBarPosition.Y + offsetY;
Canvas.SetLeft(ComponentB, newLeft);
Canvas.SetTop(ComponentB, newTop);
// 4. 更新“上一次”的鼠标位置和组件位置
_lastMousePosition = currentMousePos;

_lastTitleBarPosition = new Point(
Canvas.GetLeft(ComponentB),
Canvas.GetTop(ComponentB)
);
}
}
}
}

http://www.jsqmd.com/news/31260/

相关文章:

  • 2025 年最新测控终端厂家推荐:符合国标 + 数据透传技术,靠谱企业深度测评报告4G 测控终端/远程测控终端/物联网测控终端/测控终端 RTU 公司推荐
  • 使用Node.js开发MCP服务器入门总结
  • 2025年菊花种苗生产厂家权威推荐榜单:菊花造型/菊花花坛/菊花种苗基地源头厂家精选
  • 2025年低噪音冷却塔实力厂家权威推荐榜单:工业冷却塔/防腐蚀冷却塔/冷却塔填料源头厂家精选
  • React系列教程:2. 定义一个组件
  • go语言获取腾讯股票示例
  • 质数筛
  • 2025年11月低氮燃烧器品牌前十排名:权威评测与行业洞察
  • React系列教程:3. 管理状态
  • 2025年外墙保温装饰一体板厂家推荐:浙江欣阳嘉茂控股集团,保温装饰一体板/保温装饰板/金属保温装饰一体板/薄陶瓷保温装饰一体板/多品类适配建筑需求
  • 如何申请和设置400电话系统?
  • 传图取字小程序:高效 OCR 文字识别工具,轻松实现图片转文字
  • 2025年11月火焰检测供应商Top10权威推荐榜:海德测控居首
  • 如何优化智能客服平台的服务流程?技巧分享!
  • Grafana12安装部署
  • 11.4联考总结
  • 维语视频微信小程序系统:一站式视频服务解决方案
  • 2025年11月火焰检测厂家推荐TOP10榜单:优质选择指南
  • 20251104
  • 图的dfs和bfs遍历
  • 永久配置 Gradle 输出编码(彻底解决)
  • 2025年热风炉品厂家/工厂排名前十:徐州海德测热风炉领跑行业
  • 新麦分销商城小程序系统:一站式分销零售解决方案
  • poi-tl导出word复杂表格(单元格合并,生成复杂表格)
  • 数据库基准测试5:HammerDB压力测试完整流程
  • 2025年工业铝型材安全定制厂家推荐:工业铝型材定制实力供应商
  • CSP-S 2025口胡记
  • 2025年烘干机制造企业权威推荐榜单:污泥烘干机/滚筒烘干机/沙子烘干机设备源头厂家精选
  • LabVIEW 类型描述符
  • 小程序平台分账功能从开始到落地的完整解析