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);
    }
    else
        imageH = 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;//Hover
    this.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;
    else
        drgevent.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

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

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

相关文章

oracle查询字段类型长度等字段信息

1.查询oracle数据库的字符集 SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER NLS_CHARACTERSET; 2.查询字段长度类型 SELECT * FROM user_tab_columns WHERE table_name user AND COLUMN_NAME SNAME 请确保将user替换为您想要查询的表名。sname为字段名 这里的字…

大模型基础BERT——Transformers的双向编码器表示

大模型基础BERT——Transformers的双向编码器表示 整体概况 BERT&#xff1a;用于语言理解的深度双向Transform的预训练 论文题目&#xff1a;BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding Bidirectional Encoder Representations from…

Ceph层次架构分析

Ceph的层次结构可以从逻辑上自下向上分为以下几个层次&#xff1a; 一、基础存储系统RADOS层 功能&#xff1a;RADOS&#xff08;Reliable Autonomic Distributed Object Store&#xff09;是Ceph的底层存储系统&#xff0c;提供了分布式存储的核心功能。它是一个完整的对象存…

实验6记录网络与故障排除

实验6记录网络与故障排除 实验目的及要求&#xff1a; 通过实验&#xff0c;掌握如何利用文档记录网络设备相关信息并完成网络拓扑结构的绘制。能够使用各种技术和工具来找出连通性问题&#xff0c;使用文档来指导故障排除工作&#xff0c;确定具体的网络问题&#xff0c;实施…

【前端】技术演进发展简史

一、前端 1、概述 1990 年&#xff0c;第一个web浏览器诞生&#xff0c;Tim 以超文本语言 HTML 为基础在 NeXT 电脑上发明了最原始的 Web 浏览器。 1991 年&#xff0c;WWW诞生&#xff0c;这标志着前端技术的开始。 前端&#xff08;Front-end&#xff09;和后端&#xff08;…

【笔记】关于git和GitHub和git bash

如何推送更新的代码到github仓库 如何在此项目已经提交在别的远程仓库的基础上更改远程仓库地址&#xff08;也就是换一个远程仓库提交&#xff09; 如何删除github中的一个文件 第二版 删除github上的一个仓库或者仓库里面的某个文件_github仓库删除一个文件好麻烦-CSDN博客 …

Chromium 中sqlite数据库操作演示c++

本文主要演示sqlite数据库 增删改查创建数据库以及数据库表的基本操作&#xff0c;仅供学习参考。 一、sqlite数据库操作类封装&#xff1a; sql\database.h sql\database.cc // Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-sty…

谷歌Gemini发布iOS版App,live语音聊天免费用!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

autoDL微调训练qwen2vl大模型

autodl是一家GPU服务厂商&#xff0c;提供专业的GPU租用服务&#xff0c;秒级计费、稳定好用 先去autodl把官方的帮助文档看懂先 AutoDL帮助文档 autodl注册并登陆&#xff0c;充钱&#xff0c;根据自己的情况租用新实例 创建新实例后马上关机&#xff0c;因为有个省钱的办法…

使用大语言模型创建 Graph 数据

Neo4j 是开源的 Graph 数据库&#xff0c;Graph 数据通过三元组进行表示&#xff0c;两个顶点一条边&#xff0c;从语意上可以理解为&#xff1a;主语、谓语和宾语。GraphDB 能够通过图来表达复杂的结构&#xff0c;非常适合存储知识型数据&#xff0c;本文将通过大语言实现图数…

RDIFramework.NET Web敏捷开发框架 V6.1发布(.NET6+、Framework双引擎)

RDIFramwork.NET Web敏捷开发框架V6.1版本发布&#xff0c;本次版本更新得非常多&#xff0c;主要有全面重新设计业务逻辑代码&#xff0c;代码量减少一半以上&#xff0c;开发更加高效。底层引入最易上手的ORM框架SqlSugar&#xff0c;让开发更加便利高效。同时保持与前期版本…

vscode-相关自用插件(倒计时,时间显示,编码对齐,css等编码颜色,简体中文,git提交相关,vue项目)

1.倒计时插件 2.时间显示插件 3.编码对齐格式颜色条 4.css等编码颜色 5.简体中文 6.git提交相关 7.vue项目

推荐一款优秀的Flash幻灯片制作软件:Flash Gallery Factory

iPixSoft Flash Gallery Factory是一款优秀的Flash幻灯片制作软件&#xff0c;可以把图片变换成绚丽多彩的Flash幻灯片和Flash相册&#xff0c;并带有动画模板、过渡效果、装饰及背景音乐等功能&#xff0c;是一款不容错过的软件。 iPixSoft Flash Gallery Factory是一款最佳的…

【Linux】man 手册的使用指南

man 手册的使用指南 man手册中文版上传至资源&#xff08;用心整理&#xff0c;感谢理解&#xff01;&#xff09; man手册官方下载链接&#xff1a;https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/ man 手册页&#xff1a;https://linux.die.net/man/ Linux man…

机器学习-35-提取时间序列信号的特征

文章目录 1 特征提取方法1.1 特征提取过程1.2 两类特征提取方法2 基于数据驱动的方法2.1 领域特定特征提取2.2 基于频率的特征提取2.2.1 模拟信号2.2.2 傅里叶变换2.2.3 抽取最大幅值对应特征2.2.4 抽取峰值幅值对应特征2.3 基于统计的特征提取2.4 基于时间的特征提取3 参考附录…

redis序列化数据查询

可以看到是HashMap&#xff0c;那么是序列化的数据 那么我们来获得反序列化数据 import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import redis.clients.jedis.Jedis;public class RedisDeserializeDemo {public static…

vue3 中直接使用 JSX ( lang=“tsx“ 的用法)

1. 安装依赖 npm i vitejs/plugin-vue-jsx2. 添加配置 vite.config.ts 中 import vueJsx from vitejs/plugin-vue-jsxplugins 中添加 vueJsx()3. 页面使用 <!-- 注意 lang 的值为 tsx --> <script setup lang"tsx"> const isDark ref(false)// 此处…

uniapp 实现 ble蓝牙同时连接多台蓝牙设备,支持app、苹果(ios)和安卓手机,以及ios连接蓝牙后的一些坑

首先对 uniapp BLE蓝牙API进行封装 这里我封装了一个类&#xff1a;bluetoothService.js 代码&#xff1a; import { throttle } from lodash export default class Bluetooth {constructor() {this.device {};this.connected false;// 使用箭头函数绑定类实例的上下文&am…

波段多空强弱指标案例,源码分享

俗话说&#xff0c;涨有涨势&#xff0c;跌有跌势&#xff0c;最怕涨跌不成型。对于波段来说&#xff0c;不论上涨还是下跌&#xff0c;都是可以进行操作或者回避的。但是波动的走势&#xff0c;往往只有走完才能完全确认。那么能不能量化波段里面涨跌的强弱变化呢&#xff1f;…

第21课-C++[set和map学习和使用]

&#x1f33c;引言 C 标准模板库&#xff08;STL&#xff09;中的 set 和 map 是两种非常实用的关联式容器。它们具备快速查找、有序存储的特点&#xff0c;因而在很多需要高效数据管理的场景中被广泛应用。本文将深入讲解 set 和 map 的用法&#xff0c;并通过实际例子分析如何…