技术看点

  • WinForm自定义控件的使用
  • 自定义控件gif动画的播放

需求及效果

又来一波 C# GDI自定义控件show 。这个控件已经使用几年了,最近找出来重构一下。原来是没有边框的,那么导致导航的功能不是很突出。本来想加个效果:在执行单击时显示Loading动画,在执行完单击事件后恢复原样。这就是网页里见到的局部刷新,Ajax常用的场景。需求来自几年前一个智能储物柜项目,人机界面有个美工设计好的效果图,为了省事和通用,需要一个透明的按钮来实现导航的任务。就是控件只是设计时可见,运行时不可见。

关键点说明

1)、GraphicsPath实现矩形的圆角羽化处理

 using (GraphicsPath path = new GraphicsPath())
{
#region 羽化,圆角处理
path.StartFigure();
path.AddArc(new Rectangle(new Point(rect.X, rect.Y), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.X + Radius, rect.Y), new Point(rect.Right - Radius, rect.Y));
path.AddArc(new Rectangle(new Point(rect.Right - * Radius, rect.Y), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.Right, rect.Y + Radius), new Point(rect.Right, rect.Bottom - Radius));
path.AddArc(new Rectangle(new Point(rect.Right - * Radius, rect.Bottom - * Radius), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.Right - Radius, rect.Bottom), new Point(rect.X + Radius, rect.Bottom));
path.AddArc(new Rectangle(new Point(rect.X, rect.Bottom - * Radius), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.X, rect.Bottom - Radius), new Point(rect.X, rect.Y + Radius));
path.CloseFigure();
#endregion

要点就是画几段弧线和矩形连接起来。透明就是用了Color.FromArgb加上透明度,然后填充GraphicsPath形成透明区域。

g.FillPath(new SolidBrush(Color.FromArgb(, BackColor)), path);

2)、单窗体应用如何模块化

窗体只有一个,但操作界面好多个,由于是无人值守的应用。那么老是切换窗体操作是非常不方便的。工作区域是一个容器Panel,把每个操作界面定义成一个Panel作为只容器。

 public partial class DepositBizPanel : UserControl
{
private BackgroundStyle backgroundStyle = BackgroundStyle.Green;
/// <summary>
/// 主题风格
/// </summary>
public BackgroundStyle BackgroundStyle
{
get { return backgroundStyle; }
set
{
backgroundStyle = value;
switch (value)
{
case GreenlandExpressBox.BackgroundStyle.Blue:
BackgroundImage = Properties.Resources.jbblue;
break;
case GreenlandExpressBox.BackgroundStyle.Orange:
BackgroundImage = Properties.Resources.jborange;
break;
case GreenlandExpressBox.BackgroundStyle.Green:
BackgroundImage = Properties.Resources.jbgreen;
break;
}
Invalidate();
}
} public Panel ParentPanel
{
get;
set;
} public Bitmap QR_Barcode
{
get { return (Bitmap)pbxBarcode.Image; }
set { pbxBarcode.Image = value; }
} public DialogResult PanelDiagResult
{
get;
set;
} public DepositBizPanel(Panel parent, Bitmap barcode, BackgroundStyle style)
{
InitializeComponent();
DoubleBuffered = true;
ParentPanel = parent;
QR_Barcode = barcode;
BackgroundStyle = style;
} private void btnback_Click(object sender, EventArgs e)
{
foreach (Control panel in ParentPanel.Controls)
{
if (panel is DepositBizPanel)
{
ParentPanel.Controls.Remove(panel);
PanelDiagResult = DialogResult.Cancel;
break;
}
}
} private void btnprocessnext_Click(object sender, EventArgs e)
{
foreach (Control panel in ParentPanel.Controls)
{
if (panel is DepositBizPanel)
{
ParentPanel.Controls.Remove(panel);
PanelDiagResult = DialogResult.OK;
break;
}
}
}
}

人机操作界面例子

3)、控件播放gif动画

private void BeginAnimate()
{
if (m_AnimateImage == null)
return;
if (ImageAnimator.CanAnimate(m_AnimateImage))
{
//当gif动画每隔一定时间后,都会变换一帧,那么就会触发一事件,  
//该方法就是将当前image每变换一帧时,都会调用当前这个委托所关联的方法。  
ImageAnimator.Animate(m_AnimateImage, m_evthdlAnimator);
}
}
private void StopAnimate()
{
if (m_AnimateImage == null)
return;
try
{
if (ImageAnimator.CanAnimate(m_AnimateImage))
{
ImageAnimator.StopAnimate(m_AnimateImage, m_evthdlAnimator);
}
}
finally
{
m_IsExecuted = false;
}
}
private void UpdateImage()
{
if (m_AnimateImage == null)
return;
if (ImageAnimator.CanAnimate(m_AnimateImage))
{
//获得当前gif动画的下一步需要渲染的帧,当下一步任何对当前gif动画的操作都是对该帧进行操作)  
ImageAnimator.UpdateFrames(m_AnimateImage);
}
}
private void OnImageAnimate(Object sender, EventArgs e)
{
Invalidate();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string s1 = @"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";
byte[] buffer = Convert.FromBase64String(s1);
MemoryStream ms = new MemoryStream(buffer);
var srcImg = Image.FromStream(ms);
m_AnimateImage = srcImg;
}

OnLoad执行的操作是从base64字符串里反序列化图片,就是效果图中的Loading的gif图片。这里遇到一个问题:在关闭了MemoryStream之后,会出现“gdi+ 中发生一般性错误”,于是改为不关闭了,控件销毁之后占用的内存就会释放吧。这是一点隐忧,如果有好的办法,希望留言告知。

透明按钮自定义控件全部代码

第一版自定义按钮:

/// <summary>
/// Cool透明自定义按钮
/// </summary>
public partial class CoolTransparentButton : UserControl
{
private Size iconSize = new Size(, );
public Size IconSize
{
get
{
return iconSize;
}
set
{
iconSize = value;
Invalidate();
}
}
private string _ButtonText;
public string ButtonText
{
get { return _ButtonText; }
set
{
_ButtonText = value;
Invalidate();
}
}
protected Image _IconImage;
public Image IconImage
{
get
{
return _IconImage;
}
set
{
_IconImage = value;
Invalidate();
}
}
private bool _FocseActived = false;
private Color _BorderColor = Color.White;
public Color BorderColor
{
get
{
return _BorderColor;
}
set
{
_BorderColor = value;
Invalidate();
}
}
private int _Radius = ;
public int Radius
{
get
{
return _Radius;
}
set
{
_Radius = value;
Invalidate();
}
}
private bool ifDrawBorderWhenLostFocse = true;
/// <summary>
/// 失去焦点是否画边框
/// </summary>
public bool IfDrawBorderWhenLostFocse
{
get
{
return ifDrawBorderWhenLostFocse;
}
set
{
ifDrawBorderWhenLostFocse = value;
Invalidate();
}
}
/// <summary>
/// 是否处于激活状态(焦点)
/// </summary>
public bool FocseActived
{
get { return _FocseActived; }
set
{
_FocseActived = value;
Invalidate();
}
}
public CoolTransparentButton()
{
DoubleBuffered = true;
BackColor = Color.Transparent;
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.Opaque, false);
UpdateStyles();
}
protected override void OnPaint(PaintEventArgs e)
{
var rect = ClientRectangle;
rect.Inflate(-, -);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
using (GraphicsPath path = new GraphicsPath())
{
#region 羽化,圆角处理
path.StartFigure();
path.AddArc(new Rectangle(new Point(rect.X, rect.Y), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.X + Radius, rect.Y), new Point(rect.Right - Radius, rect.Y));
path.AddArc(new Rectangle(new Point(rect.Right - * Radius, rect.Y), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.Right, rect.Y + Radius), new Point(rect.Right, rect.Bottom - Radius));
path.AddArc(new Rectangle(new Point(rect.Right - * Radius, rect.Bottom - * Radius), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.Right - Radius, rect.Bottom), new Point(rect.X + Radius, rect.Bottom));
path.AddArc(new Rectangle(new Point(rect.X, rect.Bottom - * Radius), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.X, rect.Bottom - Radius), new Point(rect.X, rect.Y + Radius));
path.CloseFigure();
#endregion
if (!FocseActived)
{
if (ifDrawBorderWhenLostFocse)
g.DrawPath(new Pen(Color.Gray, ), path);
g.FillPath(new SolidBrush(Color.FromArgb(, BackColor)), path);
}
else
{
g.DrawPath(new Pen(BorderColor, ), path);
rect.Inflate(-, -);
g.FillPath(new SolidBrush(Color.FromArgb(, BackColor)), path);
}
#region 画文本
g.SmoothingMode = SmoothingMode.AntiAlias;
if (IconImage != null)
{
Rectangle rc = new Rectangle((Width - ) / , , IconSize.Width, IconSize.Height);
g.DrawImage(IconImage, rc);
}
if (!string.IsNullOrEmpty(ButtonText))
{
using (StringFormat f = new StringFormat())
{
Rectangle rectTxt = new Rectangle(, (Height - ) / , Width, );
f.Alignment = StringAlignment.Center;// 水平居中对齐
f.LineAlignment = StringAlignment.Center; // 垂直居中对齐
f.FormatFlags = StringFormatFlags.NoWrap;// 设置为单行文本
SolidBrush fb = new SolidBrush(this.ForeColor); // 绘制文本
e.Graphics.DrawString(ButtonText, new Font("微软雅黑", 16F, FontStyle.Bold), fb, rectTxt, f);
}
}
#endregion
}
}
protected override void OnMouseHover(EventArgs e)
{
FocseActived = true;
}
protected override void OnMouseLeave(EventArgs e)
{
FocseActived = false;
}
protected override void OnEnter(EventArgs e)
{
FocseActived = true;
}
protected override void OnLeave(EventArgs e)
{
FocseActived = false;
}
}

第二版自定义按钮:

/// <summary>
/// 自定义透明自定义按钮,模仿实现了网页元素的Ajax效果
/// </summary>
public partial class AjaxTransparentButton : UserControl
{
private Size iconSize = new Size(, );
public Size IconSize
{
get
{
return iconSize;
}
set
{
iconSize = value;
Invalidate();
}
}
private string _ButtonText;
public string ButtonText
{
get { return _ButtonText; }
set
{
_ButtonText = value;
Invalidate();
}
}
protected Image _IconImage;
public Image IconImage
{
get
{
return _IconImage;
}
set
{
_IconImage = value;
Invalidate();
}
}
private bool _FocseActived = false;
private Color _BorderColor = Color.White;
public Color BorderColor
{
get
{
return _BorderColor;
}
set
{
_BorderColor = value;
Invalidate();
}
}
private int _Radius = ;
public int Radius
{
get
{
return _Radius;
}
set
{
_Radius = value;
Invalidate();
}
}
private bool ifDrawBorderWhenLostFocse = true;
/// <summary>
/// 失去焦点是否画边框
/// </summary>
public bool IfDrawBorderWhenLostFocse
{
get
{
return ifDrawBorderWhenLostFocse;
}
set
{
ifDrawBorderWhenLostFocse = value;
Invalidate();
}
}
/// <summary>
/// 是否处于激活状态(焦点)
/// </summary>
public bool FocseActived
{
get { return _FocseActived; }
set
{
_FocseActived = value;
Invalidate();
}
}
private Image m_AnimateImage = null;
private EventHandler m_evthdlAnimator = null;
private bool m_IsExecuted = false;
public AjaxTransparentButton()
{
BackColor = Color.Transparent;
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
SetStyle(ControlStyles.Opaque, false);
UpdateStyles();
m_evthdlAnimator = new EventHandler(OnImageAnimate);
}
protected override void OnPaint(PaintEventArgs e)
{
var rect = ClientRectangle;
rect.Inflate(-, -);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
using (GraphicsPath path = new GraphicsPath())
{
#region 羽化,圆角处理
path.StartFigure();
path.AddArc(new Rectangle(new Point(rect.X, rect.Y), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.X + Radius, rect.Y), new Point(rect.Right - Radius, rect.Y));
path.AddArc(new Rectangle(new Point(rect.Right - * Radius, rect.Y), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.Right, rect.Y + Radius), new Point(rect.Right, rect.Bottom - Radius));
path.AddArc(new Rectangle(new Point(rect.Right - * Radius, rect.Bottom - * Radius), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.Right - Radius, rect.Bottom), new Point(rect.X + Radius, rect.Bottom));
path.AddArc(new Rectangle(new Point(rect.X, rect.Bottom - * Radius), new Size( * Radius, * Radius)), , );
path.AddLine(new Point(rect.X, rect.Bottom - Radius), new Point(rect.X, rect.Y + Radius));
path.CloseFigure();
#endregion
if (!FocseActived)
{
if (ifDrawBorderWhenLostFocse)
g.DrawPath(new Pen(Color.Gray, ), path);
g.FillPath(new SolidBrush(Color.FromArgb(, BackColor)), path);
}
else
{
g.DrawPath(new Pen(BorderColor, ), path);
rect.Inflate(-, -);
g.FillPath(new SolidBrush(Color.FromArgb(, BackColor)), path);
}
#region 画文本
g.SmoothingMode = SmoothingMode.AntiAlias;
if (IconImage != null)
{
Rectangle rc = new Rectangle((Width - ) / , , IconSize.Width, IconSize.Height);
g.DrawImage(IconImage, rc);
}
if (!string.IsNullOrEmpty(ButtonText))
{
using (StringFormat f = new StringFormat())
{
Rectangle rectTxt = new Rectangle(, (Height - ) / , Width, );
f.Alignment = StringAlignment.Center;// 水平居中对齐
f.LineAlignment = StringAlignment.Center; // 垂直居中对齐
f.FormatFlags = StringFormatFlags.NoWrap;// 设置为单行文本
SolidBrush fb = new SolidBrush(this.ForeColor); // 绘制文本
e.Graphics.DrawString(ButtonText, new Font("微软雅黑", 16F, FontStyle.Bold), fb, rectTxt, f);
}
}
if (m_AnimateImage != null)
{
Rectangle rectGif = new Rectangle((Width - ) / , (Height - ) / - , , );
if (m_IsExecuted)
{
UpdateImage();
e.Graphics.DrawImage(m_AnimateImage, rectGif);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(Color.Transparent), rectGif);
}
}
#endregion
}
}
protected override void OnMouseHover(EventArgs e)
{
FocseActived = true;
}
protected override void OnMouseLeave(EventArgs e)
{
FocseActived = false;
}
protected override void OnEnter(EventArgs e)
{
FocseActived = true;
}
protected override void OnLeave(EventArgs e)
{
FocseActived = false;
}
private void BeginAnimate()
{
if (m_AnimateImage == null)
return;
if (ImageAnimator.CanAnimate(m_AnimateImage))
{
//当gif动画每隔一定时间后,都会变换一帧,那么就会触发一事件,  
//该方法就是将当前image每变换一帧时,都会调用当前这个委托所关联的方法。  
ImageAnimator.Animate(m_AnimateImage, m_evthdlAnimator);
}
}
private void StopAnimate()
{
if (m_AnimateImage == null)
return;
try
{
if (ImageAnimator.CanAnimate(m_AnimateImage))
{
ImageAnimator.StopAnimate(m_AnimateImage, m_evthdlAnimator);
}
}
finally
{
m_IsExecuted = false;
}
}
private void UpdateImage()
{
if (m_AnimateImage == null)
return;
if (ImageAnimator.CanAnimate(m_AnimateImage))
{
//获得当前gif动画的下一步需要渲染的帧,当下一步任何对当前gif动画的操作都是对该帧进行操作)  
ImageAnimator.UpdateFrames(m_AnimateImage);
}
}
private void OnImageAnimate(Object sender, EventArgs e)
{
Invalidate();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string s1 = @"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";
byte[] buffer = Convert.FromBase64String(s1);
MemoryStream ms = new MemoryStream(buffer);
var srcImg = Image.FromStream(ms);
m_AnimateImage = srcImg;
}
protected override void OnClick(EventArgs e)
{
if (m_IsExecuted)
return;
Action clickTask = () =>
{
m_IsExecuted = true;
BeginAnimate();
base.OnClick(e);
Invalidate();
};
//异步执行单击事件
clickTask.BeginInvoke((result) =>
{
clickTask.EndInvoke(result);
m_IsExecuted = false;
StopAnimate();
}, null);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (m_AnimateImage != null)
{
try
{
StopAnimate();
}
finally
{
m_AnimateImage.Dispose();
m_evthdlAnimator = null;
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Enter)
{
OnClick(e);
}
}
}

注释不是很多,源码如有需要拿走不谢.近来访问本博的外国友人多起来了,所以在Code Project上发布了E文版的本篇博客,目前短短两个月包含我大中华帝国在内已经有29个国家地区访问本博客,这是写作的动力。

DEMO下载请猛击这里!

C# Winform 实现Ajax效果自定义按钮的更多相关文章

  1. C#自定义按钮、自定义WinForm无边框窗体、自定义MessageBox窗体

    C#自定义按钮.自定义WinForm无边框窗体.自定义MessageBox窗体 C#自定义Button按钮控件 效果展示 C#自定义Winform无边框窗体 效果展示 C#自定义无边框MessageB ...

  2. iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果

    一.转盘(裁剪图片.自定义按钮.旋转) 1.裁剪图片 将一张大图片裁剪为多张 // CGImageCreateWithImageInRect:用来裁剪图片 // image:需要裁剪的图片 // re ...

  3. Yii框架zii.widgets.grid自定义按钮,ajax触发事件并提示

    相关类手册: http://www.yiichina.com/api/CButtonColumn   buttons 属性 public array $buttons; the configurati ...

  4. php+ajax实现登录按钮加载loading效果

    php+ajax实现登录按钮加载loading效果,一个提高用户体验,二个避免重复提交表单,ajax判断加载是否完成. 登录表单 <form onsubmit="return chec ...

  5. Qt实现自定义按钮的三态效果

    好久之前做的一个小软件,好长时间没动过了,在不记录下有些细节可能都忘了,这里整理下部分功能的实现. 按钮的三态,指的是普通态.鼠标的停留态.点击态,三态是界面交互非常基本的一项功能,Qt中如果使用的是 ...

  6. django xadmin 插件(3) 列表视图新增自定义按钮

    效果图: 编辑按钮是默认的list_editable属性对应的插件(xadmin.plugins.editable) 放大按钮对应的是自定义插件. 自定义按钮源码: xplugin.py(保证能够直接 ...

  7. dataTable之自定义按钮实现全表 复制 打印 导出 重载

    //本文对常用表格插件datatable 的自定义按钮功能键进行详细解释//其中 15-78行是定义表单//16 18 19 三行定义自定义功能按钮 实现对全表的 复制 打印 导出(csv即excel ...

  8. (三)c#Winform自定义控件-有图标的按钮

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  9. WPF自定义控件与样式(2)-自定义按钮FButton

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

随机推荐

  1. IdentityServer4 SigningCredential(RSA 证书加密)

    IdentityServer4 默认提供了两种证书加密配置: services.AddIdentityServer() .AddDeveloperSigningCredential() .AddTem ...

  2. Java开发必装的IntelliJ IDEA插件

    IDEA 插件简介 常见的IDEA插件主要有如下几类: 常用工具支持 Java日常开发需要接触到很多常用的工具,为了便于使用,很多工具也有IDEA插件供开发使用,其中大部分已经在IDEA中默认集成了. ...

  3. float 浮动

    浮动最开始的目的是为了让文字环绕图片(一个图片和多行文字对齐)   1.包裹性:元素添加 float 属性之后 自动变成 inline-block 元素,能设置 宽高 2.破坏性:破坏自身高度,还会使 ...

  4. Centos7下部署ceph 12.2.1 (luminous)集群及RBD使用

    前言 本文搭建了一个由三节点(master.slave1.slave2)构成的ceph分布式集群,并通过示例使用ceph块存储. 本文集群三个节点基于三台虚拟机进行搭建,节点安装的操作系统为Cento ...

  5. PTA 数据结构 银行业务队列简单模拟

    仅供参考,请勿粘贴 设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 -- 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客.给定到达银行的顾客序列,请按业务完 ...

  6. redhat7 Samba

    1.先安装Samba服务 yum install -y samba samba-client 2.配置文件 vi /etc/samba/smb.conf  --主配置文件 [global]  --全局 ...

  7. Thrift全面介绍

    官网:http://thrift.apache.org   简介 Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java ...

  8. [转载] java多线程学习-java.util.concurrent详解(一) Latch/Barrier

    转载自http://janeky.iteye.com/blog/769965     Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可 ...

  9. UWP 返回顶部按钮

    返回顶部的按钮,like this 当用户下滑了一定的距离之后,通常是快滑倒底部的时候,出现返回顶部按钮,当用户向上快滑,滑到顶部的时候,返回顶部按钮自动消失. 在UWP中,用来滚动内容的控件是Scr ...

  10. 微信小程序开发《三》:微信小程序请求不能使用session的原因及解决办法

    本人在前面的微信小程序开发<二>中提到要想在服务端保持状态需要在客户端第一次请求服务器的时候给客户端返回一个sessionid,由客户端在本地保存,下次请求的时候在header里面带上这个 ...