C#中Winform 实现Ajax效果自定义按钮

技术看点

  1. WinForm自定义控件的使用
  2. 自定义控件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(2 * Radius, 2 * Radius)), 180, 90);
    path.AddLine(new Point(rect.X + Radius, rect.Y), new Point(rect.Right - Radius, rect.Y));
    path.AddArc(new Rectangle(new Point(rect.Right - 2 * Radius, rect.Y), new Size(2 * Radius, 2 * Radius)), 270, 90);
    path.AddLine(new Point(rect.Right, rect.Y + Radius), new Point(rect.Right, rect.Bottom - Radius));
    path.AddArc(new Rectangle(new Point(rect.Right - 2 * Radius, rect.Bottom - 2 * Radius), new Size(2 * Radius, 2 * Radius)), 0, 90);
    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 - 2 * Radius), new Size(2 * Radius, 2 * Radius)), 90, 90);
    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(153, 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(32, 32);
  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 = 12;
  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(-1, -1);
   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(2 * Radius, 2 * Radius)), 180, 90);
    path.AddLine(new Point(rect.X + Radius, rect.Y), new Point(rect.Right - Radius, rect.Y));
    path.AddArc(new Rectangle(new Point(rect.Right - 2 * Radius, rect.Y), new Size(2 * Radius, 2 * Radius)), 270, 90);
    path.AddLine(new Point(rect.Right, rect.Y + Radius), new Point(rect.Right, rect.Bottom - Radius));
    path.AddArc(new Rectangle(new Point(rect.Right - 2 * Radius, rect.Bottom - 2 * Radius), new Size(2 * Radius, 2 * Radius)), 0, 90);
    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 - 2 * Radius), new Size(2 * Radius, 2 * Radius)), 90, 90);
    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, 1), path);
     g.FillPath(new SolidBrush(Color.FromArgb(66, BackColor)), path);
    }
    else
    {
     g.DrawPath(new Pen(BorderColor, 1), path);
     rect.Inflate(-1, -1);
     g.FillPath(new SolidBrush(Color.FromArgb(153, BackColor)), path);
    }
    #region 画文本
    g.SmoothingMode = SmoothingMode.AntiAlias;
    if (IconImage != null)
    {
     Rectangle rc = new Rectangle((Width - 32) / 2, 16, IconSize.Width, IconSize.Height);
     g.DrawImage(IconImage, rc);
    }
    if (!string.IsNullOrEmpty(ButtonText))
    {
     using (StringFormat f = new StringFormat())
     {
      Rectangle rectTxt = new Rectangle(0, (Height - 18) / 2, Width, 36);
      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(32, 32);
  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 = 12;
  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(-1, -1);
   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(2 * Radius, 2 * Radius)), 180, 90);
    path.AddLine(new Point(rect.X + Radius, rect.Y), new Point(rect.Right - Radius, rect.Y));
    path.AddArc(new Rectangle(new Point(rect.Right - 2 * Radius, rect.Y), new Size(2 * Radius, 2 * Radius)), 270, 90);
    path.AddLine(new Point(rect.Right, rect.Y + Radius), new Point(rect.Right, rect.Bottom - Radius));
    path.AddArc(new Rectangle(new Point(rect.Right - 2 * Radius, rect.Bottom - 2 * Radius), new Size(2 * Radius, 2 * Radius)), 0, 90);
    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 - 2 * Radius), new Size(2 * Radius, 2 * Radius)), 90, 90);
    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, 1), path);
     g.FillPath(new SolidBrush(Color.FromArgb(66, BackColor)), path);
    }
    else
    {
     g.DrawPath(new Pen(BorderColor, 1), path);
     rect.Inflate(-1, -1);
     g.FillPath(new SolidBrush(Color.FromArgb(153, BackColor)), path);
    }
    #region 画文本
    g.SmoothingMode = SmoothingMode.AntiAlias;
    if (IconImage != null)
    {
     Rectangle rc = new Rectangle((Width - 32) / 2, 16, IconSize.Width, IconSize.Height);
     g.DrawImage(IconImage, rc);
    }
    if (!string.IsNullOrEmpty(ButtonText))
    {
     using (StringFormat f = new StringFormat())
     {
      Rectangle rectTxt = new Rectangle(0, (Height - 18) / 2, Width, 36);
      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 - 24) / 2, (Height - 16) / 2 - 8, 32, 32);
     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);
   }
  }
 }

注释不是很多,源码如有需要拿走不谢

(0)

相关推荐

  • C# WinForm中禁止改变窗口大小的方法

    本文介绍在使用C#开发WinForm窗体程序时,如何设置窗体的大小不能被改变. 我们在开发一个窗体(WinForm)程序时,所有的控件都部署在程序界面上了,如果这时来把窗体的大小调整一下,那界面就难看了.怎么设置窗体大小不能被修改呢? 在Form类下面有一个FormBorderStyle的字段,我们可以通过设置它的值来让窗体不能被拉大拉小.FormBorderStyle的值设置为FormBorderStyle.FixedSingle或Fixed3D时,窗体大小是不能被改变的. 当然,还有一种情况

  • C#中WinForm程序退出方法技巧总结

    本文实例总结了C#中WinForm程序退出方法技巧.分享给大家供大家参考.具体分析如下: 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.ExitThread(); System.Environment.Exit(0); 等他们各自的方法不一样,下面我们就来详细介绍一下. 1.this.Close();   只是关闭当前窗口,若不是主窗体的话,是无法退出程序的,另外若有托管线程(非主线程),也无法干净地退

  • C# Winform中实现主窗口打开登录窗口关闭的方法

    在使用C#进行Winform编程时,我们经常需要使用一个登录框来进行登录,一旦输入的用户名密码登录成功,这时登录窗口应该关闭,而且同时打开主程序窗口.该如何来实现呢? 乍一想,很简单啊,打开主窗口就用主窗口的Show()方法,而关闭登录窗口就用登录窗口的Close()方法即可.即代码如下: Program.cs中代码: 复制代码 代码如下: Application.Run(new FormLogin()); 登录窗口(FormLogin)代码: 复制代码 代码如下: private void b

  • c# winform多线程的小例子

    在文本框中输入一个数字,点击开始累加按钮,程序计算从1开始累计到该数字的结果.因为该累加过程比较耗时,如果直接在UI线程中进行,那么当前窗口将出现假死.为了有更好的用户体验,程序启动一个新的线程来单独执行该计算,然后每隔200毫秒读取一次累加结果,并把结果显示到文本框下方的label控件中.同时,程序支持取消操作,点击取消累计按钮,程序将取消累加操作,并把当前累加值显示到label中.为了方便后面的描述,我把UI线程称作主线程,把执行累加计算的线程称作工作者线程.该过程有两个关键点: 1:如何在

  • c# winform窗口一直置顶显示在桌面最上方或最底层的方法

    一. 在最前面: using System.Runtime.InteropServices; 在定义部分引入下面两个函数: [DllImport( "user32 ")] private static extern IntPtr FindWindow(string lpClassName,string lpWindowName); [DllImport( "user32 ")] private static extern IntPtr SetParent(IntPt

  • C#(WinForm) ComboBox和ListBox添加项及设置默认选择项

    Web控件DropDownList和WinForm控件ComboBox机制不一样. ComboBox没有对应的ListItem需要自己写一个: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WinListItem { /// <summary> /// 选择项类,用于ComboBox或者ListBox添加项 /// </summary>

  • c# winform取消右上角关闭按钮的实现方法

    一种方法是可以在窗体的属性面板将窗体的 ControlBox属性设置为false,或者在窗体的构造函数中这样写: 复制代码 代码如下: public Form1() { InitializeComponent(); this.ControlBox = false;   // 设置不出现关闭按钮 } 不过这样做的话,会连同最小化和最大化按钮都给弄掉了,所以,如果你想只想让关闭按钮不起作用,然后保留最小化.最大化的话,就重写窗体的CreateParams方法: 复制代码 代码如下: //禁用窗体的关

  • C#中winform使用相对路径读取文件的方法

    本文实例讲述了C#中winform使用相对路径读取文件的方法.分享给大家供大家参考.具体分析如下: 目录结构如下图所示:   方法一:由于生成的exe文件在bin\debug目录下,可以使用向上查找目录的方式获取要读取的xml文件 复制代码 代码如下: string haarXmlPath = @"../../haarcascade_frontalface_alt_tree.xml"; FileInfo file = new FileInfo(fileName); string  fu

  • C#,winform,ShowDialog,子窗体向父窗体传值

    调用showdialog方法后,调用代码被暂停执行,等到调用showdialog方法的窗体关系后再继续执行.而且窗体可以返回一个dialogresult值,他描述了窗体关闭的原因,例如OK,Cancel,yes,no等.为了让窗体返回一个dialogresult,必须设置窗体的dialogresult值,或者在窗体的一个按钮上设置dialogresult属性. 例子: 下面是子窗体代码,要求输入phone,然后会返回给父窗体. using System; using System.Collect

  • C#中Winform 实现Ajax效果自定义按钮

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

  • Android UI设计系列之自定义SwitchButton开关实现类似IOS中UISwitch的动画效果(2)

    做IOS开发的都知道,IOS提供了一个具有动态开关效果的UISwitch组件,这个组件很好用效果相对来说也很绚丽,当我们去点击开关的时候有动画效果,但遗憾的是Android上并没有给我们提供类似的组件(听说在Android4.0的版本上提供了具有动态效果的开关组件,不过我还没有去看文档),如果我们想实现类似的效果那该怎么办了呢?看来又得去自定义了. 公司的产品最近一直在做升级,主要做的就是把界面做的更绚丽更美观给用户更好的体验(唉,顾客是上帝......),其中的设置功能中就有开关按钮,原来的开

  • vue-video-player 通过自定义按钮组件实现全屏切换效果【推荐】

    最近公司的产品上线,一些高级功能在基础版本中不对用户开发,通过视频的形式展示. 产品开发用的是 vue, 经同事介绍使用了vue-video-player视频播放插件,通过 demo案例很快实现了视频播放效果 <video-player class="vjs-custom-skin" ref="videoPlayer1" :options="playerOptions" :playsinline="true" :even

  • vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知

    vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知 使用element-ui中的Notification,只有一个message属性是有很大的操作空间,其余的都是写死的,无法进行扩展,达不到想要的效果.所以只能在message上下功夫. 在element-ui官方文档中可以看到Notification中的message属性是可以处理VNode的所以我们可以使用VNode来达到我们需要的效果. 如何关闭通知呢? 当创建通知的时候,会返回该通知的实

  • 微信小程序中的video视频实现 自定义播放按钮、封面图、视频封面上文案

    效果图展示: 实现方法: 在video中添加一个cover-view,在cover-view写两个cover-image,一个用来存储封面图.一个用来存放播放按钮,同级写一个cover-view用来完成封面上的文字,设置绝对定位,水平垂直居中,在播放按钮上添加点击事件,点击之后隐藏cover-view,最后在监听视频结束事件,重新填充封面跟播放按钮就可以了. 代码: <video id="myVideo" src="{{videoSrc}}" enable-d

  • jQuery插件uploadify实现ajax效果的图片上传

    昨天做了一天的ajax效果的图片上传,就是想让自己学的更加的精一些,所以看了很多第三方的控件,最后还是选择了uploadify这个控件,主要原因是比较容易上手. 首先我们先参考别人的资料(我自己整理了一下) 可选项 需要参数类型 参数名字 解释 (布尔型) auto 当文件被添加到队列时,自动上传. (字符串) buttonImg 浏览按钮的背景图片路径. (字符串) buttonText 默认在按钮上显示的文本. (字符串) cancelImg 取消按钮的背景图片路径. (字符串) check

  • JavaScript中浅讲ajax图文详解

    1.ajax入门案例 1.1 搭建Web环境 ajax对于各位来说,应该都不陌生,正因为ajax的产生,导致前台页面和服务器之间的数据传输变得非常容易,同时还可以实现页面的局部刷新.通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新. 对于JavaWeb项目而言,ajax主要用于浏览器和服务器之间数据的传输. 如果是单单地堆砌知识点,会显得比较无聊,那么根据惯例,我先不继续介绍ajax,而是来写一个案例吧. 打开

  • Easyui Datagrid自定义按钮列(最后面的操作列)

    做项目的时候因为需求,要在表格的最后添加一列操作列,easyUI貌似没有提供这种功能,不过没关系,我们可以自定义来实现 版本:jQuery easyUI 1.3.2 这里我的实现方式是采用HTML形式,js方式暂时还没用到 首先是HTML部分 <table id="dg" title="学生信息" class="easyui-datagrid" url="${ctx}listStudent.do" toolbar=&qu

  • 不使用XMLHttpRequest对象实现Ajax效果的方法小结

    本文实例讲述了不使用XMLHttpRequest对象实现Ajax效果的方法.分享给大家供大家参考,具体如下: 前言: 我以前接触Ajax的时候,只是用Jquery的api来实现Ajax效果,对其并没有细细研究,最近在学习Ajax的原理,会不定时的发布关于Ajax的文章,希望大家关注! Ajax原理: 在页面不刷新的情况下,利用XMLHttpRequest发送HTTP请求. 主题: 但是不依靠XMLHttpRequest对象,也是可以实现Ajax效果的,我们可以用Js实现对后台服务器的请求,同时不

  • C# WPF 自定义按钮的方法

    本文介绍WPF一种自定义按钮的方法. 实现效果 使用图片做按钮背景: 自定义鼠标进入时效果: 自定义按压效果: 自定义禁用效果 实现效果如下图所示: 实现步骤 创建CustomButton.cs,继承自Button: 创建一个资源文件ButtonStyles.xaml: 在资源文件中设计按钮的Style: 在CustomButton.cs中添加Style中需要的依赖属性: 在程序中添加资源并引用(为了方便在不同的程序中引用自定义按钮,自定义按钮放在独立的类库中,应用程序中进行资源合并即可). 示

随机推荐