C#用户控件之转换开关

如何自定义一个转换键(Toggle)?

三步绘制一个精美控件:

  1. 定义属性;
  2. 画布重绘;
  3. 添加事件;

主要技能:

  • 如何自定义属性;
  • 画布重绘的一般格式;
  • 控件的事件触发过程;
  • 技能扩展
    1. 转换按钮使能时添加二次确认弹框?

    2. 在From窗体中应用控件时,点击事件没有触发?

    3. 属性名称在控件属性树中的排列如何定义?

    4. 添加一个字体更改属性?

1.定义属性

  • 字体(Font)
  • 颜色(Color)
  • 字符串(String)
  • 枚举(Enum)
  • 属性说明 [Browsable(true)]
#region 属性

private Font displayFont = new Font("Segoe UI", 12);
[Browsable(true)]
[Category("布局_G")]
[Description("字体格式")]
public Font DisplayFont
{
get { return displayFont; }
set
{
if (value != null)
{
displayFont = value;
this.Invalidate(); // Trigger redraw
}
}
} private bool _checked = false;
[Browsable(true)] //说明(需放在属性前边):是否选中
[Category("布局_G")]
[Description("是否选中")]
public bool Checked
{
get { return _checked; }
set
{
_checked = value;
this.Invalidate(); //激活触发事件
this.MouseDown_G?.Invoke(this, null); }
} private string falseText = "关闭";
[Browsable(true)] //说明:文本关闭
[Category("布局_G")]
[Description("文本关闭")]
public string FalseText
{
get { return falseText; }
set { falseText = value; this.Invalidate(); }
} //样式切换
public enum SwType
{
Ellipse, //椭圆
Rectangle, //矩形
} private SwType switchType = SwType.Ellipse;
[Browsable(true)] //说明:切换样式
[Category("布局_G")]
[Description("切换样式")]
public SwType SwitchType
{
get { return switchType; }
set { switchType = value; this.Invalidate(); }
} private Color sliderColor = Color.White; //Color.White
[Browsable(true)] //说明:滑块颜色
[Category("布局_G")]
[Description("滑块颜色")]
public Color SliderColor
{
get { return sliderColor; }
set { sliderColor = value; this.Invalidate(); }
} #endregion

属性名称在控件属性树中的排列如何定义?

答:根据属性说明安装A~Z的字母顺序排列

2.画布重绘

  • 画带四角圆弧的矩形、滑块、文本;
  • 画椭圆、滑块、文本
      #region 画布

      private Graphics graphics;
private int width;
private int height; //矩形绘制
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
graphics = e.Graphics;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; this.width = this.Width;
this.height = this.Height; if (this.switchType == SwType.Rectangle) //字段选择为矩形时
{
//填充色
Color fillColor = this._checked ? trueColor : falseColor; //带四角圆弧的矩形
GraphicsPath path = new GraphicsPath();
int diameter = 10; //默认圆弧直径
//左上角圆弧:起始坐标,宽,高,开始角度,扫描角度
path.AddArc(0, 0, diameter, diameter, 180f, 90f);
path.AddArc(this.width - diameter, 0, diameter, diameter, 270f, 90f); //右上角
path.AddArc(this.width - diameter, this.height - diameter, diameter, diameter, 0f, 90f); //右下角
path.AddArc(0, this.height - diameter, diameter, diameter, 90f, 90f); //左下角
graphics.FillPath(new SolidBrush(fillColor), path); //填充色 //文本
string strText = this._checked ? trueText : falseText; //滑块(true\false 两种形态)
if (_checked)
{
//绘制滑块
path = new GraphicsPath();
int sliderwidth = this.height - 4;
path.AddArc(this.width - sliderwidth - 2, 2, diameter, diameter, 180f, 90f);
path.AddArc(this.width - diameter - 2, 2, diameter, diameter, 270f, 90f);
path.AddArc(this.width - diameter - 2, this.height - diameter - 2, diameter, diameter, 0f, 90f);
path.AddArc(this.width - sliderwidth - 2, this.height - diameter - 2, diameter, diameter, 90f, 90f);
graphics.FillPath(new SolidBrush(sliderColor), path); //绘制文本
Rectangle rec = new Rectangle(0, 0, this.width - sliderwidth - 2, this.height);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center; graphics.DrawString(strText, DisplayFont, new SolidBrush(sliderColor), rec, sf); }
else
{
//绘制滑块
path = new GraphicsPath();
int sliderwidth = this.height - 4;
path.AddArc(2, 2, diameter, diameter, 180f, 90f);
path.AddArc(sliderwidth - diameter + 2, 2, diameter, diameter, 270f, 90f);
path.AddArc(sliderwidth - diameter + 2, sliderwidth - diameter + 2, diameter, diameter, 0f, 90f);
path.AddArc(2, sliderwidth - diameter + 2, diameter, diameter, 90f, 90f);
graphics.FillPath(new SolidBrush(sliderColor), path); //绘制文本
Rectangle rec = new Rectangle(sliderwidth + 2, 0, this.width - sliderwidth - 2, this.height);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graphics.DrawString(strText, DisplayFont, new SolidBrush(sliderColor), rec, sf);
}
}
else if (this.switchType == SwType.Ellipse) //字段选择为椭圆时
{
//填充色
Color fillColor = this._checked ? trueColor : falseColor; //椭圆形
GraphicsPath path = new GraphicsPath(); path.AddArc(1, 1, this.height - 2, this.height - 2, 90f, 180f);
path.AddArc(this.width - (this.height - 2) - 1, 1, this.height - 2, this.height - 2, 270f, 180f);
graphics.FillPath(new SolidBrush(fillColor), path); //填充色 //文本
string strText = this._checked ? TrueText : falseText; //滑块(true\false 两种形态)
if (_checked)
{
//绘制滑块
int ciclewidth = this.height - 6;
graphics.FillEllipse(new SolidBrush(sliderColor), new Rectangle(this.width - ciclewidth - 3, 3, ciclewidth, ciclewidth)); //绘制文本
Rectangle rec = new Rectangle(0, 0, this.width - ciclewidth - 3, this.height);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graphics.DrawString(strText, DisplayFont, new SolidBrush(sliderColor), rec, sf);
}
else
{
//绘制滑块
int ciclewidth = this.height - 6; graphics.FillEllipse(new SolidBrush(sliderColor), new Rectangle(3, 3, ciclewidth, ciclewidth)); //绘制文本
Rectangle rec = new Rectangle(ciclewidth + 3, 0, this.width - ciclewidth - 3, this.height);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graphics.DrawString(strText, DisplayFont, new SolidBrush(sliderColor), rec, sf);
}
}
} #endregion

3.添加事件

理解 :在From中控件的鼠标点击事件的执行过程

先执行控件内部的MouseDown方法——其方法内部的属性——其属性中的触发事件——最后执行From后台的点击生成的自定义方法(可自定义)

其他技巧: 应用控件时拉出来双击即可生成自定义方法

<From中双击控件默认是Load方法,想让他自动生成自己设置的事件需要在控件代码中添加:[DefaultEvent("MouseDown_G")]>。

//指定默认事件(双击控件进入)
[DefaultEvent("MouseDown_G")]

关键代码:点击控件弹出框确认后再执行From的事件中的代码


//事件声明 public event EventHandler MouseDown_G;

//激活事件 this.MouseDown_G?.Invoke(this, null); ——执行完成跳转到From中的双击事件方法中


//构造函数添加鼠标点击事件——点击控件事件处理
this.MouseDown += Toggle_MouseDown;
//构造函数添加事件处理后自动生成此方法(无需在控件的属性中双击)
private void Toggle_MouseDown(object sender, MouseEventArgs e)
{
DialogResult dr = MessageBox.Show("二次确认操作?", "提示您", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (dr == DialogResult.OK)
{
Checked = !Checked;
}
else return;
}

发现一个错误,当应用该控件时,在From中点击无效;经过两天的查询(断点查询)才发现问题所在,在Form的设计器中的From属性的Enable为False,改为true才可使能

原因:控件更新后没有及时生成导致From崩盘后(空窗口后没在意),导致Designer的默认代码更改。


End

讨论交流请留言

C#自定义控件—转换开关的更多相关文章

  1. android自定义控件一站式入门

    自定义控件 Android系统提供了一系列UI相关的类来帮助我们构造app的界面,以及完成交互的处理. 一般的,所有可以在窗口中被展示的UI对象类型,最终都是继承自View的类,这包括展示最终内容的非 ...

  2. ASP.NET MVC学习之母版页和自定义控件的使用

    一.母板页_Layout.cshtml类似于传统WebForm中的.master文件,起到页面整体框架重用的目地1.母板页代码预览 <!DOCTYPE html> <html> ...

  3. C# 自定义控件VS用户控件

    1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Con ...

  4. 自定义控件之 圆形 / 圆角 ImageView

    一.问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的:       二.怎么搞? 机智的我,第一想法就是,切一张中间圆形透明.四周与底色相同.尺寸与头像相同的蒙板图片,盖在 ...

  5. 如何开发FineReport的自定义控件?

    FineReport作为插件化开发的报表软件,有些特殊需求的功能需要自己开发,开发的插件包帆软官方有提提供,可以去帆软论坛上找,本文将主要介绍如何开发一个自定义控件,这里讲讲方法论. 第一步:实例化一 ...

  6. WPF自定义控件第二 - 转盘按钮控件

    继之前那个控件,又做了一个原理差不多的控件.这个控件主要模仿百度贴吧WP版帖子浏览界面左下角那个弹出的按钮盘.希望对大家有帮助. 这个控件和之前的也差不多,为了不让大家白看,文章最后发干货. 由于这个 ...

  7. 【Win 10应用开发】AdaptiveTrigger在自定义控件中是可以触发的

    前些天,看到有网友给我留言,说AdaptiveTrigger在自定义控件(模板化控件)中不能触发.因为当时我正在写其他的代码,就没有去做实验来验证,于是我就给这位网友提了使用GotoVisualSta ...

  8. WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

    一.前言.预览 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要是对文本 ...

  9. Android自定义控件之自定义ViewGroup实现标签云

    前言: 前面几篇讲了自定义控件绘制原理Android自定义控件之基本原理(一),自定义属性Android自定义控件之自定义属性(二),自定义组合控件Android自定义控件之自定义组合控件(三),常言 ...

  10. Android自定义控件之自定义组合控件

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...

随机推荐

  1. 韦东山freeRTOS系列教程之【第五章】队列(queue)

    目录 系列教程总目录 概述 5.1 队列的特性 5.1.1 常规操作 5.1.2 传输数据的两种方法 5.1.3 队列的阻塞访问 5.2 队列函数 5.2.1 创建 5.2.2 复位 5.2.3 删除 ...

  2. JavaSE 计算2个List集合中的交集、差集、并集、去重并集

    VideoOrder.java 重写里面的equals和hashCode方法 class VideoOrder { private int price; private String title; p ...

  3. Python代码学习

    1.生成四位数字字母验证码,大小写字母随机 import random if __name__ =="__main__": #四位数字字母验证码的生成 checkcode=&quo ...

  4. 1. CMake 概述

    1. CMake 概述 CMake 可以用来构建C/C++工程,可以跨平台.允许开发者指定整个工程的编译流程 在CMake 没有出来之前,开发者需要手写 makefile,但是不同平台下的 makef ...

  5. 利用opencv库使用Python将视频逐帧转为图片

    做成型的语义分割软件需要,写了一个,在博客记录一下 import cv2 def video2pic(videoFile, outputFile): vc = cv2.VideoCapture(vid ...

  6. Vue 数组和对象更新,但视图未更新,背后的故事

    在实际开发中,遇到遍历数组和对象,当property 发生改变时,并没有触发视图的更新今天来浅显的聊聊这背后的故事,有说的不对地方,还望指出! 本人博文地址:https://www.cnblogs.c ...

  7. JMeter 配置元件之按条件读取CSV Data Set Config

    实践环境 win10 JMeter 5.4.1 需求描述 需求是这样的,需要压测某个接口(取消分配接口),请求这个接口之前,需要先登录系统(物流WMS系统),并在登录后,选择并进入需要操作的仓库,然后 ...

  8. Prometheus 使用Python推送指标数据到Pushgateway

    使用Python推送指标数据到Pushgateway 需求描述 实践环境 Python 3.6.5 Django 3.0.6 prometheus-client 0.11.0 代码实现 !/usr/b ...

  9. [rCore学习笔记 021]多道程序与分时任务

    写在前面 本随笔是非常菜的菜鸡写的.如有问题请及时提出. 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 导读 ...

  10. 神奇的发现——所有的aarch64架构的CPU平台下的深度学习框架均不原生支持CUDA

    一个记录: 神奇的发型--所有的aarch64架构的CPU平台下的深度学习框架均不原生支持CUDA 不论是mindspore.pytorch.TensorFlow框架只要是aarch64架构的CPU下 ...