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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu将firewall-config导出为.deb文件

firewall-config ubuntu是canonial 公司维护的&#xff0c;用wireshark测过&#xff0c;开机会给他们公司发遥测&#xff08;开了ufw阻塞所有连接也一样&#xff0c;canonial在里面把代码改了&#xff09;firewall-config是fedora(爱好者维护&#xff0c;公益版本)自带的防火墙…

蓝桥杯备考——算法

一、排序 冒泡排序、选择排序、插入排序、 快速排序、归并排序、桶排序 二、枚举 三、二分查找与二分答案 四、搜索&#xff08;DFS&#xff09; DFS&#xff08;DFS基础、回溯、剪枝、记忆化&#xff09; 1.DFS算法&#xff08;深度优先搜索算法&#xff09; 深度优先搜…

Javascript垃圾回收机制-运行机制(大厂内部培训版本)

前言 计算机基本组成&#xff1a; 我们编写的软件首先读取到内存&#xff0c;用于提供给 CPU 进行运算处理。 内存的读取和释放&#xff0c;决定了程序性能。 冯诺依曼结构 解释和编译 这两个概念怎么理解呢。 编译相当于事先已经完成了可以直接用。好比去饭店吃饭点完上…

python面向对象基础入门

面向对象 基本的实现方法大概如此 class Student(object):def __init__(self, name, score):self.name nameself.score scoredef print_score(self):print(%s: %s % (self.name, self.score))在面向对象的思想中&#xff0c;面对一个问题&#xff0c;首先应该考虑这个问题所…

阿里云ACK容器如何配置pod分散在集群的不同节点上

阿里云ACK容器如何配置pod分散在集群的不同节点上 1.核心原理 是使用pod间反亲和性&#xff08;podAntiAffinity&#xff09;&#xff0c;pod间反亲和性又分为软约束反亲和和硬约束反亲和。 2.软约束反亲和和硬约束反亲和区别&#xff1a; preferredDuringSchedulingIgnore…

ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息显示等功能

一、简介 本播放器是在vs2019 x86下开发&#xff0c;通过ffmpeg实现拉流解码功能&#xff0c;通过D3D实现视频的渲染功能。截图功能采用libjpeg实现&#xff0c;可以截取jpg图片&#xff0c;图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现&#x…

怎样遵守编程规范,减少和控制C++编程中出现的bug?

遵守编程规范和最佳实践是减少和控制 C 编程中出现 bug 的重要手段。以下是一些具体的建议和策略&#xff0c;帮助你编写更健壮、更易于维护的 C 代码。 1. 遵循 C 标准和最佳实践 使用现代 C 特性&#xff1a;尽可能使用 C11 及之后的标准&#xff0c;避免使用过时的特性和库…

从零开始学习 sg200x 多核开发之 uboot 网络功能使能

sophpi u-boot 默认未开启网络功能&#xff0c;需要手动开启&#xff0c;为了在 u-boot 下可以通过 tftp 下载固件&#xff0c;先测试 u-boot 下网络功能。 u-boot 网络功能开启 在 build/boards/cv181x/sg2002_wevb_riscv64_sd/u-boot/cvitek_sg2002_wevb_riscv64_sd_defcon…

编译sddm 0.18.1 依赖

github 下载后cmake编译会出现一些依赖 Could not find a package configuration file provided by "ECM" 则执行 sudo apt install extra-cmake-modules PAM headers not found - configure: 解决方法 yum -y install pam-devel No package ‘xcb-xkb’ foun…

C++11标准模板(STL)- 常用数学函数 - 宏常量 - 求值得到float类型的安静NaN(NAN)

常用数学函数 求值得到float类型的安静NaN NAN 定义于头文件 <math.h> #define NAN /*implementation defined*/ (C99 起) 宏 NAN 展开成求值为安静非数&#xff08; QNaN &#xff09;的 float 类型常量表达式。若实现不支持 QNaN &#xff0c;则不定义此宏。 用于打…

NodeJS 百度智能云文本转语音(实测)

现在文本转语音的技术已经非常完善了&#xff0c;尽管网络上有许多免费的工具&#xff0c;还是测试了专业的服务&#xff0c;选择了百度的TTS服务。 于是&#xff0c;在百度智能云注册和开通了文本转语音的服务&#xff0c;尝试使用NodeJS 实现文本转语音服务。但是百度的文档实…

信也科技和云杉网络的AI可观测性实践分享

1. 信也科技 2、云杉网络 2.1 中国移动

SQLite 安装指南

SQLite 安装指南 SQLite 是一种轻量级的数据库管理系统,因其小巧、快速和易于使用而广受欢迎。本指南将详细介绍如何在不同的操作系统上安装 SQLite,并确保您能够顺利开始使用它。 1. Windows 系统上的安装 1.1 下载 SQLite 访问 SQLite 官方网站:sqlite.org/download.ht…

【项目开发】Web App vs Native App,开发者作何选择?

文章目录 引言市场需求与机会竞技场的右侧:为移动屏幕优化的 Web 应用移动 Web 应用的优缺点移动 Web 应用的优势移动版Web应用的缺点引言 在建立稳固的移动网络存在感并为用户提供流畅的移动体验时,移动网络应用的必要性已经不再是可选项。然而,随着移动原生应用的兴起,出…

解析煤矿一张图

解析煤矿一张图 ​ 煤矿一张图是指通过数字化、智能化技术将煤矿的各项信息、数据和资源进行集中展示和管理&#xff0c;形成一个综合的可视化平台。这一平台将矿井的地理信息、设备状态、人员位置、安全生产、环境监测等信息整合成一个统一的“图形”&#xff0c;以便于管理者…

管家婆工贸ERP BR039.采购订单关联MRP明细表

最低适用版本&#xff1a; 工贸系列 23.8 插件简要功能说明&#xff1a; 采购订单明细表&#xff0c;支持显示采购订单明细上游请购单明细关联的MRP中对应销售订单明细产成品相关信息更多细节描述见下方详细文档 插件操作视频&#xff1a; 进销存类定制插件--采购订单关联M…

SpringBootTest常见错误解决

1.启动类所在包错误 问题 由于启动类所在包与需要自动注入的类的包不在一个包下&#xff1a; 启动类所在包&#xff1a; com.exmaple.test_02 但是对于需要注入的类却不在com.exmaple.test_02下或者其子包下&#xff0c;就会导致启动类无法扫描到该类&#xff0c;从而无法对…

Java 全栈知识体系

包含: Java 基础, Java 部分源码, JVM, Spring, Spring Boot, Spring Cloud, 数据库原理, MySQL, ElasticSearch, MongoDB, Docker, k8s, CI&CD, Linux, DevOps, 分布式, 中间件, 开发工具, Git, IDE, 源码阅读&#xff0c;读书笔记, 开源项目...

高效管理生产线:哪些项目管理工具最适合制造企业?

制造业的生产管理往往涉及复杂的流程和多部门协作&#xff0c;如何确保各环节顺利对接、信息准确传递&#xff0c;是每一家制造企业都在不断优化的问题。面对这些管理难题&#xff0c;越来越多的制造企业引入了项目管理软件&#xff0c;通过直观的任务分配、进度跟踪、数据反馈…

微信小程序 https://thirdwx.qlogo.cn 不在以下 downloadFile 合法域名列表中

授权登录后&#xff0c;拿到用户头像进行加载&#xff0c;但报错提示&#xff1a; https://thirdwx.qlogo.cn 不在以下 downloadFile 合法域名列表中 解决方法一&#xff08;未完全解决&#xff0c;临时处理&#xff09;&#xff1a;在微信开发者工具将不校验...勾上就可以访问…