C#中的Drawing 类案例详解

2025-08-08 21:50

本文主要是介绍C#中的Drawing 类案例详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《C#中的Drawing类案例详解》文章解析WPF与WinForms的Drawing类差异,涵盖命名空间、继承链、常用类及应用场景,通过案例展示如何创建带阴影圆角矩形按钮,强调WPF的轻量、可动画特...

一、Drawing 是什么?

命名空间

  • wpF:System.Windows.Media
  • WinForms:System.Drawing(GDI+)

继承链(WPF)

  • Object → DispatcherObject → DependencyObject → Freezable → Animatable → Drawing

常用派生类:

  • GeometryDrawing(用 Path 画形状)
  • ImageDrawing(贴位图)
  • VideoDrawing(播放视频)
  • GlyphRunDrawing(文字)
  •  DrawingGroup(容器,可组合其它 Drawing)

特点

  • 轻量级:只存“矢量指令”,不继承 UIElement,不参与布局/事件路由。
  • 可冻结(Freeze):变为只读后可跨线程使用。
  • 可序列化/导出为 XAML。

二、典型用法

  • 直接放在控件里
  • 用 DrawingBrush 或 DrawingImage 把 Drawing 变成 Brush/Image,再赋给控件的 Background、Source 等属性。
  • 在 DrawingVisual 里绘制
  • 适合自定义控件、命中测试、打印。
  • 在 DrawingGroup 里组合
  • 把多个 Drawing 套娃,实现复杂场景。

三、案例:画一个“带阴影的圆角矩形按钮”

目标:

  • 圆角矩形(填充线性渐变、描边)
  • 下方有一层模糊阴影(半透明黑圆角矩形)
  •  鼠标悬停时整体高亮(动画改变渐变)

WPF:

<Window x:Class="DemoDrawing.MainWindow"
        XMLns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Drawing 示例" Width="300" Height="200">
    <Grid>
        <!-- 使用 DrawingBrush 做背景 -->
        <Rectangle x:Name="btnRect" Width="180" Height="60"
                   MouseEnter="BtnRect_MouseEnter"
                   MouseLeave="BtnRect_MouseLeave">
            <Rectangle.Resources>
                <!-- 阴影 Drawing -->
                <GeometryDrawing x:Key="shadow"
                                 Geometry="M 5,5 175,5 175,55 5,55 Z"
                                 Brush="#80000000">
                    <GeometryDrawing.Pen>
                        <Pen Brush="Transparent" Thickness="1"/>
                    </GeometryDrawing.Pen>
                </GeometryDrawingChina编程>
                <!-- 按钮主体 Drawing -->
                <GeometryDrawing x:Key="body" Geometry="M 0,0 170,0 170,50 0,50 Z">
                    <GeometryDrawing.Brush>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                            <GradientStop Offset="0"  Color="#FF4C9AFF"/>
                            <GradientStop Offset="1"  Color="#FF0050DD"/>
                        </LinearGradientBrush>
                    </GeometryDrawing.Brush>
                    <GeometryDrawing.Pen>
                        <Pen Brush="#FF003399" Thickness="2"/>
                    </GeometryDrawing.Pen>
                </GeometryDrawing>
                <!-- 组合 DrawingGroup -->
                <DrawingGroup x:Key="combined">
                    <!-- 先画阴影 -->
                    <DrawingGroup.Children>
                        <DrawingGroup>
                            <DrawingGroup.Children>
                                <StaticResource ResourceKey="shadow"/>
                            </DrawingGroup.Children>
                            <DrawingGroup.BitmapEffect>
                                <BlurBitmapEffect Radius="5"/>
                            </DrawingGroup.BitmapEffect>
                        </DrawingGroup>
                        <!-- 再画按钮主体 -->
                        <StaticResource ResourceKey="body"/>
                    </DrawingGroup.Children>
                </DrawingGroup>
                <!-- 把 DrawingGroup 变成 Brush -->
                <DrawingBrush x:Key="btnBrush" Drawing="{StaticResource combined}"/>
            </Rectangle.Resources>
            <Rectangle.Fill>
                <StaticResource ResourceKey="btnBrush"/>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
</Window>

后台代码

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void BtnRect_MouseEnter(object sender, MouseEventArgs e)
    {
        // 找到 Drawing 里的渐变刷
        var rect = (Rectangle)sender;
        var brush = (DrawingBrush)rect.Fill;
        var dg = (DrawingGrouprfcEgVVOr)brush.Drawing;
        var body = (GeometryDrawing)((DrawingGroup)dg.Children[1]).Children[0];
        var lg = (phpLinearGradientBrush)body.Brush;
        // 动画高亮
        var da = new ColorAnimation(Color.FromRgb(0x6F, 0xBA, 0xFF),
                                    TimeSpan.FromMilliseconds(300));
        lg.GradientStops[0].BeginAnimation(GradientStop.ColorProperty, da);
    }
    private void BtnRect_MouseLeave(object sender, MouseEventArgs e)
    {
   rfcEgVVOr     var rect = (Rectangle)sender;
        var brush = (DrawingBrush)rect.Fill;
        var dg = (DrawingGroup)brush.Drawing;
        var body = (GeometryDrawing)((DrawingGroup)dg.Chihttp://www.chinasem.cnldren[1]).Children[0];
        var lg = (LinearGradientBrush)body.Brush;
        var da = new ColorAnimation(Color.FromRgb(0x4C, 0x9A, 0xFF),
                                    TimeSpan.FromMilliseconds(300));
        lg.GradientStops[0].BeginAnimation(GradientStop.ColorProperty, da);
    }
}

四、WinForms(GDI+)对应写法

WinForms 没有 Drawing 类,而是 GraphicsPath + LinearGradientBrush + Bitmap 的“即时模式”绘制。核心步骤:

protected override void OnPaint(PaintEventArgs e)
{
    var g = e.Graphics;
    g.SmoothingMode = SmoothingMode.AntiAlias;
    // 1. 阴影
    using (var path = CreateRoundRect(5, 5, 175, 55, 8))
    using (var brush = new SolidBrush(Color.FromArgb(128, 0, 0, 0)))
    using (var blur = new Bitmap(180, 60))
    {
        using (var g2 = Graphics.FromImage(blur))
        {
            g2.SmoothingMode = SmoothingMode.AntiAlias;
            g2.FillPath(brush, path);
        }
        // 手动高斯模糊(略)...
        g.DrawImage(blur, 0, 0);
    }
    // 2. 主体
    using (var path = CreateRoundRect(0, 0, 170, 50, 8))
    using (var brush = new LinearGradientBrush(
        new Point(0, 0), new Point(0, 50),
        Color.FromArgb(255, 0x4C, 0x9A, 0xFF),
        Color.FromArgb(255, 0x00, 0x50, 0xDD)))
    using (var pen = new Pen(Color.FromArgb(255, 0x00, 0x33, 0x99), 2))
    {
        g.FillPath(brush, path);
        g.DrawPath(pen, path);
    }
}
private GraphicsPath CreateRoundRect(float x, float y, float w, float h, float r)
{
    var gp = new GraphicsPath();
    gp.AddArc(x + w - r, y, r, r, 270, 90);
    gp.AddArc(x + w - r, y + h - r, r, r, 0, 90);
    gp.AddArc(x, y + h - r, r, r, 90, 90);
    gp.AddArc(x, y, r, r, 180, 90);
    gp.CloseFigure();
    return gp;
}
  •  WPF 的 Drawing 体系是“矢量指令树”,轻量、可缓存、可动画,适合高性能场景(千级图形)。
  •  常用套路:GeometryDrawing/DrawingGroup → DrawingBrush/DrawingImage → Shape 或 Image 控件。
  •  WinForms 没有 Drawing 类,用 Graphics 即时绘制;想缓存可用 Bitmap/ Metafile。

到此这篇关于C#Drawing 类详解的文章就介绍到这了,更多相关C# Drawing 类内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于C#中的Drawing 类案例详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155648

相关文章

Kotlin 协程之Channel的概念和基本使用详解

《Kotlin协程之Channel的概念和基本使用详解》文章介绍协程在复杂场景中使用Channel进行数据传递与控制,涵盖创建参数、缓冲策略、操作方式及异常处理,适用于持续数据流、多协程协作等,需注... 目录前言launch / async 适合的场景Channel 的概念和基本使用概念Channel 的

C#使用SendMessage实现进程间通信的示例代码

《C#使用SendMessage实现进程间通信的示例代码》在软件开发中,进程间通信(IPC)是关键技术之一,C#通过调用WindowsAPI的SendMessage函数实现这一功能,本文将通过实例介绍... 目录第一章:SendMessage的底层原理揭秘第二章:构建跨进程通信桥梁2.1 定义通信协议2.2

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

SpringBoot AspectJ切面配合自定义注解实现权限校验的示例详解

《SpringBootAspectJ切面配合自定义注解实现权限校验的示例详解》本文章介绍了如何通过创建自定义的权限校验注解,配合AspectJ切面拦截注解实现权限校验,本文结合实例代码给大家介绍的非... 目录1. 创建权限校验注解2. 创建ASPectJ切面拦截注解校验权限3. 用法示例A. 参考文章本文

Java中字符编码问题的解决方法详解

《Java中字符编码问题的解决方法详解》在日常Java开发中,字符编码问题是一个非常常见却又特别容易踩坑的地方,这篇文章就带你一步一步看清楚字符编码的来龙去脉,并结合可运行的代码,看看如何在Java项... 目录前言背景:为什么会出现编码问题常见场景分析控制台输出乱码文件读写乱码数据库存取乱码解决方案统一使

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

Redis 的 SUBSCRIBE命令详解

《Redis的SUBSCRIBE命令详解》Redis的SUBSCRIBE命令用于订阅一个或多个频道,以便接收发送到这些频道的消息,本文给大家介绍Redis的SUBSCRIBE命令,感兴趣的朋友跟随... 目录基本语法工作原理示例消息格式相关命令python 示例Redis 的 SUBSCRIBE 命令用于订