C#/WinForm拖拽文件上传

news/2024/11/17 2:36:45 标签: c#, 开发语言

 

一、首先创建一个上传文件的类,继承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


http://www.niftyadmin.cn/n/5754815.html

相关文章

Restful API接⼝简介及为什么要进⾏接⼝压测

一、RESTful API简介 在现代Web开发中&#xff0c;RESTful API已经成为一种标准的设计模式&#xff0c;用于构建和交互网络应用程序。本文将详细介绍RESTful API的基本概念、特点以及如何使用它来设计高效的API接口。 1. 基于协议 HTTP 或 HTTPS RESTful API通常使用HTTP&am…

STM32 标准库函数 GPIO_SetBits、GPIO_ResetBits、GPIO_WriteBit、GPIO_Write 区别

GPIO_SetBits&#xff1a; 使用例&#xff1a; GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);意思是将GPIOA1和GPIOA2设为高电平 GPIO_SetBits(GPIOA, 0x0003);意思也是将GPIOA1和GPIOA2设为高电平 实际上当选中GPIOA时&#xff0c;它会按位遍历&#xff0c;在哪一位有1说…

后端——接口文档(API)

一、概念 后端的接口文档&#xff08;API文档&#xff09;——全称为应用程序编程接口&#xff08;Application Programming Interface&#xff09;文档&#xff0c;是详细阐述特定软件应用程序或Web服务所开放接口的具体使用指南。这份文档为开发者提供了与这些接口进行交互的…

全面解读 USB Key:定义、使用场景、加密技术及 Java 实现

文章目录 **什么是 USB Key&#xff1f;****USB Key 的使用场景**1. **身份认证**2. **数字签名**3. **数据加密与解密**4. **证书管理** **USB Key 解决的问题****USB Key 使用的加密技术**1. **对称加密**2. **非对称加密**3. **哈希算法**4. **数字签名**5. **PKI&#xff0…

【Python爬虫实战】轻量级爬虫利器:DrissionPage之SessionPage与WebPage模块详解

&#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、SessionPage &#xff08;一&#xff09;SessionPage 模块的基本功能 &#xff08;二&#xff09;基本使…

【ubuntu18.04】vm虚拟机复制粘贴键不能用-最后无奈换版本

我是ubuntu16版本的 之前费老大劲安装的vmware tools结果不能用 我又卸载掉&#xff0c;安装了open-vm-tools 首先删除VMware tools sudo vmware-uninstall-tools.pl sudo rm -rf /usr/lib/vmware-tools sudo apt-get autoremove open-vm-tools --purge再下载open-vm-tools s…

vue3: toRef, reactive, toRefs, toRaw

vue3&#xff1a; toRef, reactive, toRefs, toRaw 扫码或者点击文字后台提问 <template><div>{{ man }}</div><hr><!-- <div>{{ name }}--{{ age }}--{{ like }}</div> --><div><button click"change">修…

Kafka入门:Java客户端库的使用

在现代的分布式系统中&#xff0c;消息队列扮演着至关重要的角色&#xff0c;而Apache Kafka以其高吞吐量、可扩展性和容错性而广受欢迎。本文将带你了解如何使用Kafka的Java客户端库来实现生产者&#xff08;Producer&#xff09;和消费者&#xff08;Consumer&#xff09;的基…