C#/WinForm拖拽文件上传

一、首先创建一个上传文件的类,继承Control类,如下:
public class UploadControl : Control{private Image _image;public UploadControl(){this.SetStyle(ControlStyles.UserPaint | //控件自行绘制,而不使用操作系统的绘制ControlStyles.AllPaintingInWmPaint | //忽略背景擦除的Windows消息,减少闪烁,只有UserPaint设为true时才能使用。ControlStyles.OptimizedDoubleBuffer |//在缓冲区上绘制,不直接绘制到屏幕上,减少闪烁。ControlStyles.ResizeRedraw | //控件大小发生变化时,重绘。ControlStyles.SupportsTransparentBackColor, //支持透明背景颜色true);_image =Properties.Resources.upload;this.Cursor = Cursors.Hand;this.AllowDrop = true;}}
准备好上传的图片

二、我们需要绘制圆角矩形,所以先准备一个圆角路径,如下:
private GraphicsPath GetRoundedRectPath(Rectangle rect, uint radius){int r = (int)radius << 1;Rectangle arcRect = new Rectangle(rect.Location, new Size(r, r));GraphicsPath path = new GraphicsPath();path.AddArc(arcRect, 180, 90);// 右上圆弧arcRect.X = rect.Right - r;path.AddArc(arcRect, 270, 90);// 右下圆弧arcRect.Y = rect.Bottom - r;path.AddArc(arcRect, 0, 90);// 左下圆弧arcRect.X = rect.Left;path.AddArc(arcRect, 90, 90);path.CloseFigure();return path;}
三、重写OnPaint事件,绘制填充圆角背景
Rectangle outRect = new Rectangle(0, 0, this.Width, this.Height);
using var outPath = GetRoundedRectPath(outRect, Radius);
this.Region = new Region(path);
using SolidBrush b = new SolidBrush(this.BackColor);
e.Graphics.FillPath(b, outPath);
效果如下:

发现使用Region属性有锯齿,尽管开启高质量绘图也无用,我们去掉Region属性,但是新的问题出现,此控件的背景必须和父级窗体的背景一致,不然圆角效果就没有了。后续我们都是不设置Region属性,保持背景与父级控件背景一致就行。
四、在OnPaint事件,绘制圆角边框
var innerRect = Rectangle.Inflate(outRect, -(int)border, -(int)border);
using GraphicsPath innerPath = GetRoundedRectPath(innerRect, Radius - border);
using Pen pen = new Pen(ColorState switch
{ControlState.Hover => this.BorderHoverColor,ControlState.Pressed => this.BorderPressedColor,ControlState.DragEnter => this.BorderHoverColor,_ => this.BorderNormalColor,
}, border);
pen.DashStyle = BorderStyle;
e.Graphics.DrawPath(pen, innerPath);
效果如下:

四、在OnPaint事件,绘制上传图像以及文字
const int h = 5;
SizeF sizeF = SizeF.Empty;
if (!string.IsNullOrWhiteSpace(Text))sizeF = e.Graphics.MeasureString(Text, this.Font);
if (_image != null)
{int imageH = 0;if (sizeF != SizeF.Empty){imageH = (int)((this.Height - _image.Height - h - sizeF.Height) / 2);TextRenderer.DrawText(e.Graphics, Text, this.Font, new Point((int)((this.Width - sizeF.Width) / 2), imageH + _image.Height + h), this.ForeColor);}elseimageH = this.Height - _image.Height >> 1;e.Graphics.DrawImage(_image, this.Width - _image.Width >> 1, imageH);
}
else
{if (sizeF != SizeF.Empty){TextRenderer.DrawText(e.Graphics, Text, this.Font, new Point((int)((this.Width - sizeF.Width) / 2), (int)((this.Height - sizeF.Height) / 2)), this.ForeColor);}
}
效果如下:

五、我们定义一个枚举,用来实现鼠标移、出移入、点击、文件拖动让边框变色
public enum ControlState { Hover, Normal, Pressed, DragEnter }
然后重写OnMouseEnter、OnMouseLeave、OnMouseDown、OnMouseUp事件,如下:
private ControlState ColorState { get; set; }= ControlState.Normal;
protected override void OnMouseEnter(EventArgs e)//鼠标进入时
{ColorState = ControlState.Hover;//Hoverthis.Invalidate();base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)//鼠标离开
{ColorState = ControlState.Normal;//正常this.Invalidate();base.OnMouseLeave(e);
}
protected override void OnMouseDown(MouseEventArgs e)//鼠标按下
{if (e.Button == MouseButtons.Left && e.Clicks == 1)//鼠标左键且点击次数为1{ColorState = ControlState.Pressed;//按下的状态this.Invalidate();using OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.Filter = "所有文件 (*.*)|*.*";if (openFileDialog.ShowDialog() == DialogResult.OK){FilesCallback?.Invoke(new string[] { openFileDialog.FileName });}}base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)//鼠标弹起
{if (e.Button == MouseButtons.Left && e.Clicks == 1){if (ClientRectangle.Contains(e.Location))//控件区域包含鼠标的位置{ColorState = ControlState.Hover;}else{ColorState = ControlState.Normal;}this.Invalidate();}base.OnMouseUp(e);
}
就是在OnPaint事件中笔的颜色代码:
ColorState switch
{ControlState.Hover => this.BorderHoverColor,ControlState.Pressed => this.BorderPressedColor,ControlState.DragEnter => this.BorderHoverColor,_ => this.BorderNormalColor,
}
当然我们在OnMouseDown事件中还实现了点击选择文件:
using OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "所有文件 (*.*)|*.*";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{FilesCallback?.Invoke(new string[] { openFileDialog.FileName });
}
其中FilesCallback是一个事件:
public event Action<string[]> FilesCallback;
六、实现文件拖动上传
protected override void OnDragEnter(DragEventArgs drgevent)
{base.OnDragEnter(drgevent);if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))drgevent.Effect = DragDropEffects.Copy;elsedrgevent.Effect = DragDropEffects.None;ColorState = ControlState.DragEnter;this.Invalidate();
}
protected override void OnDragLeave(EventArgs e)
{base.OnDragLeave(e);ColorState = ControlState.Normal;this.Invalidate();
}
protected override void OnDragDrop(DragEventArgs drgevent)
{base.OnDragDrop(drgevent);ColorState = ControlState.Normal;this.Invalidate();object? obj = drgevent.Data?.GetData(DataFormats.FileDrop);if (obj == null) return;FilesCallback?.Invoke((string[])obj);
}
同时需要在构造函数中开启AllowDrop:
this.AllowDrop = true;

其它代码未在这里展示详情请见:
https://gitee.com/feng-cai/Seal-Bubbles
相关文章:
C#/WinForm拖拽文件上传
一、首先创建一个上传文件的类,继承Control类,如下: public class UploadControl : Control{private Image _image;public UploadControl(){this.SetStyle(ControlStyles.UserPaint | //控件自行绘制,而不使用操作系统的绘制Cont…...
IT运维的365天--019 用php做一个简单的文件上传工具
前情提要:朋友的工作室,有几个网站分布在不同的服务器上,要经常进行更新,之前是手动复制压缩包到各个服务器去更新(有写了自动更新的Shell脚本)。但还是觉得太麻烦,每次还要手动传输压缩包到各个…...
详细的oracle rac维护命令集合
一、查看命令 所有实例和服务的状态 $srvctl status database -d orcl Instance orcl1 is running on node db1 Instance orcl2 is running on node db2 单个实例的状态 $ srvctl status instance -d orcl -i orcl2 Instance orcl2 is running on node db2 单个节点的应用程序…...
23 种设计模式详解
设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、 组合模…...
Python毕业设计选题:基于django+vue的二手物品交易系统
开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 店铺管理 二手物品管理 广告管理 留言反馈 订单…...
VMware 17虚拟Ubuntu 22.04设置共享目录
VMware 17虚拟Ubuntu 22.04设置共享目录 共享文件夹挂载命令!!!<font colorred>配置启动自动挂载Chapter1 VMware 17虚拟Ubuntu 22.04设置共享目录一、卸载老版本二、安装open-vm-tools<font colorred>三、配置启动自动挂载四、添…...
Rust学习(五):泛型、trait
Rust学习(五):泛型、trait 1、泛型: 相信小伙伴们一定还记得,之前我们实现了一个add函数,并指定了参数类型为:i32: fn add(x:i32, y:i32) ->i32 {x y }这里我们就会遇到一个问…...
智能零售柜商品识别
项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…...
2024智能机器人与自动控制国际学术会议 (IRAC 2024)
主办,承办,支持单位 会议官网 www.icirac.org 大会时间:2024年11月29-12月1日 大会简介 2024智能机器人与自动控制国际学术会议 (IRAC 2024)由华南理工大学主办,会议将于2024年11月29日-12月1日在中国广…...
计算机组成原理:总线与微命令
实验四 总线与微命令实验 一、实验目的 1) 理解总线的概念和作用。 2) 连接运算器与存储器,熟悉计算机的数据通路。 3) 理解微命令与微操作的概念。 二、实验要求 1) 做好实验预习,在实验之前填写好…...
10月回顾 | Apache SeaTunnel社区动态与进展一览
各位热爱 Apache SeaTunnel 的小伙伴们,社区10月份月报来啦,请查收! 这里将记录Apache SeaTunne社区每月动态和进展,欢迎关注。 月度Merge之星 感谢以下小伙伴上个月为 Apache SeaTunnel 所做的精彩贡献(排名不分先…...
网络基础(4)传输层
既然是传输层首先就要明确实在层状结构的哪里,除开物理层之外分成了四层协议: 到这里上层(应用层)的使用已经没有问题,之前使用的套接字都是在应用层的。 再说端口号 到一个主机收到一个报文的时候,这个报文中一定存在这个报文需要到的主机的ip号。如果…...
计算机的错误计算(一百五十六)
摘要 探讨 MATLAB 中双曲反余切函数 acoth(x) 在 附近数的计算精度问题。 Acoth(x)函数的定义为 例1. 已知 计算 与 直接贴图吧: 另外,16位的正确值分别为 0.1110083774360105e2 与 -0.1110083774360105e2(ISRealsoft 提供。通过计算…...
爬虫开发工具与环境搭建——开发工具介绍
第二章:爬虫开发工具与环境搭建 第一节 开发工具介绍 爬虫开发需要一些合适的工具和框架来高效地抓取网页数据。在这节中,我们将介绍常用的开发工具,帮助开发者快速搭建爬虫开发环境。 1. Python与爬虫框架选择 Python因其简洁、易学的语法…...
Oracle 19c PDB克隆后出现Warning: PDB altered with errors受限模式处理
在进行一次19c PDB克隆过程中,发现克隆结束,在打开后出现了报错,PDB变成受限模式,以下是分析处理过程 09:25:48 SQL> alter pluggable database test1113 open instancesall; Warning: PDB altered with errors. Elapsed: 0…...
阿里云ACK容器如何配置pod分散在集群的不同节点上
阿里云ACK容器如何配置pod分散在集群的不同节点上 1.核心原理 是使用pod间反亲和性(podAntiAffinity),pod间反亲和性又分为软约束反亲和和硬约束反亲和。 2.软约束反亲和和硬约束反亲和区别: preferredDuringSchedulingIgnore…...
Qt信号和槽
信号和槽的概念 在Linux中我们也学过信号 Signal,这是进程间通信的一种方式,这里大致分为三个要素: 信号源:谁发送的信号(用户进程,系统内核,终端或者作业控制,) 信号的类…...
Python知识点精汇!字符串:定义、截取(索引)和其内置函数
目录 一、字符串的定义 二、字符串的截取 1.截取干啥的 2.怎么用截取 3.打印多次 4.两个字符串拼接在一起 三、字符串内置函数 1.查询函数: (1)find(str,start,end) (2)index(str,start,end&#…...
【CV】头盔检测区域入侵项目
文章目录 🌕项目和数据下载🌙安全帽佩戴数据集🌕收集数据数据🌕wbem格式视频转avi或者mp4🌕跑通区域入侵🌙多边形标注工具下载🌙使用Python脚本打开视频获取一张用来标注的图片🌙打开labelme标注一个多边行🌙程序可以识别的标注json格式🌙修改代码读取Json…...
大数据应用开发——实时数据处理(一)
前言 大数据应用开发——实时数据采集 大数据应用开发——实时数据处理 Flink完成Kafka中的数据消费,将数据分发至Kafka的dwd层中 并在HBase中进行备份 大数据应用开发——数据可视化 hadoop,zookeeper,kafka,flink要开启 目…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
