在我们一些非标的用户界面中,我们往往需要自定义用户控件界面,从而实现不同的内容展示和处理规则,本篇内容介绍使用Winform开发自定义用户控件,以及实现相关自定义事件的处理。

1、用户控件的界面分析

对于比较规范的界面,需要进行一定的分析,以便从中找到对应的规则,逐步细化为自定义用户控件的方式。例如对于由下面多个集合组成的界面内容。

我们截取其中之一,也就是有这些内容多个组合而成,集合可以通过布局TableLayoutPanel(表格布局)或者FlowLayoutPanel(顺序流布局)来添加即可。

而其中之一的内容,不同的颜色方格又可以定义为一个用户控件,因此最终有多个小方格组成的用户控件的。

而单个用户控件,可能承载不同的内容,我们可以定义更多的接口属性以及一些事件来处理相关的逻辑。

甚至,我能还可以在一个单元格里面放置更多的内容,如放置一些特殊的标签来展示信息。

2、自定义用户控件的接口和实现

为了使用户控件更加规范化,我们可以定义一个接口,声明相关的属性和处理方法,如下代码所示。

    /// <summary>
/// 自定义控件的接口
/// </summary>
public interface INumber
{
/// <summary>
/// 数字
/// </summary>
string Number { get; set; } /// <summary>
/// 数值颜色
/// </summary>
Color Color { get; set; } /// <summary>
/// 显示文本
/// </summary>
string Animal { get; set; } /// <summary>
/// 显示文本
/// </summary>
string WuHan { get; set; } /// <summary>
/// 设置选中的内容的处理
/// </summary>
/// <param name="data">事件数据</param>
void SetSelected(ClickEventData data);
}

然后我们创建一个用户控件,并命名为NumberItem,并使它继承前面定义的接口 INumber ,实现相关的属性和事件,如下代码所示。

    /// <summary>
/// 自定义用户控件
/// </summary>
public partial class NumberItem : UserControl, INumber
{
/// <summary>
/// 数字
/// </summary>
public string Number { get; set; } /// <summary>
/// 颜色
/// </summary>
public Color Color { get; set; } /// <summary>
/// 显示文本
/// </summary>
public string Animal { get; set; } /// <summary>
/// 显示文本
/// </summary>
public string WuHan { get; set; }

其中处理方法SetSelected先保留为空,后面继续完善。

        /// <summary>
/// 设置选中的数值
/// </summary>
/// <param name="data">传递的数据</param>
public void SetSelected(ClickEventData data)
{ }

由于自定义控件,我们需要跟踪用户的单击处理,并且需要把这个逻辑逐步推动到顶级界面上去进行处理,因此需要定义一个事件信息,如下所示。

        /// <summary>
/// 事件处理
/// </summary>
public EventHandler<ClickEventData> ClickEventHandler { get; set; }

其中ClickEventData是我们定义的一个数据,用来承载用户单击的类型和值内容的信息结构,如下代码所示。

   /// <summary>
/// 对自定义控件触发的事件信息
/// </summary>
public class ClickEventData
{
/// <summary>
/// 事件触发类型
/// </summary>
public ClickEventType ClickEventType { get; set; } = ClickEventType.Number; /// <summary>
/// 传递值
/// </summary>
public string Value { get; set; } public ClickEventData()
{
} /// <summary>
/// 参数化构造
/// </summary>
/// <param name="clickEventType">事件触发类型</param>
/// <param name="value">传递值</param>
public ClickEventData(ClickEventType clickEventType, string value)
{
ClickEventType = clickEventType;
Value = value;
}
}

在创建一个整合多个号码数值的一个自定义控件,他也是一个完整的单元之一,我们命名为 LotteryItemControl2。

我们相当于把前面的自定义控件,组合为一个新的用户控件,形成一个相对完整的部分,这里提供两种思路,一种是使用常规的用户控件,拖动已有的用户控件组合而成,如下所示。

另一种是利用TableLayoutPanel,动态添加控件进行组合,可以根据预设的TableLayout布局实现控件的顺序添加。

表格的行列定义如下所示

两种方式都可以实现类似的效果,我们这里以第一种为例实现。

    public partial class LotteryItemControl2 : UserControl
{
/// <summary>
/// 事件处理
/// </summary>
public EventHandler<ClickEventData> ClickEventHandler { get; set; } /// <summary>
/// 第几期
/// </summary>
public string Qi { get; set; } /// <summary>
/// 数据列表
/// </summary>
public List<string> NumberList { get; set; }

数据列表就是展示在自定义控件的数字。在控件中定义一个函数 统一处理数据内容的绑定显示。

        /// <summary>
/// 绑定数据
/// </summary>
public void BindData()
{
//控件列表,方便统一处理
var controlList = new List<NumberItem>
{
this.numberItem1, this.numberItem2, this.numberItem3, this.numberItem4,
this.numberItem5, this.numberItem6, this.numberItem7
}; this.labelQi.Text = Qi; //设置第几期
for(int i =0; i < this.NumberList.Count; i++)
{
var control = controlList[i];
var number = this.NumberList[i]; var shenxiao = LotteryToolHelper.NumberToShenXiaoDict[number]; //"马";
var wuhan = LotteryToolHelper.NumberToWuhanDict[number];//"土" control.Number = number;
control.Animal = shenxiao;
control.WuHan = wuhan; var colorStr = LotteryToolHelper.ColorBall[number];
control.Color = LotteryToolHelper.GetColor(colorStr); //item % 2 == 0 ? Color.Red : Color.Green; control.BindData();
control.ClickEventHandler += (s, data) =>
{
if (ClickEventHandler != null)
{
//传递父控件统一处理
ClickEventHandler(s, data);
}
};
}
}

其中该控件也可以设置选中,有具体的子控件调用设置选中的处理规则即可。

        /// <summary>
/// 遍历控件,设置选中的数值
/// </summary>
/// <param name="data">传递信息</param>
public void SetSelected(ClickEventData data)
{
foreach (var control in this.Controls)
{
if (control is NumberItem item)
{
item.SetSelected(data);
}
}
}

为了提高性能,我们一般往往需要设置窗体或者Panel为双缓冲DoubleBuffered = true。

在主界面的面板中,我们可以添加一个FlowLayoutPanel 来按顺序堆叠用户控件,具体的实现逻辑就是根据从数据库获得的记录进行展示即可。

    var controlList = new List<LotteryItemControl2>();
foreach (var info in list)
{
var control = new LotteryItemControl2(); control.Qi = info.LineNo.ToString("D2");
var numberList = new List<string>()
{
info.No1.ToString("D2"),
info.No2.ToString("D2"),
info.No3.ToString("D2"),
info.No4.ToString("D2"),
info.No5.ToString("D2"),
info.No6.ToString("D2"),
info.No7.ToString("D2"),
};
control.NumberList = numberList;
control.BindData(); control.ClickEventHandler += (s, data) =>
{
//遍历所有的控件统一处理样式
foreach (var subCtrl in panel.Controls)
{
if (subCtrl is LotteryItemControl2 lottery)
{
lottery.SetSelected(data);
}
}
};
controlList.Add(control);
}
this.panel.Controls.AddRange(controlList.ToArray());

以上就是相关的处理逻辑,用来组织自定义用户控件的统一展示处理。

如果需要用户进行不同条件的数据展示,那么展示前,就需要重新清空面板中的控件,如下所示。

            //清空界面
while (panel.Controls.Count > 0)
{
var controltoremove = panel.Controls[0];
panel.Controls.RemoveAt(0);
controltoremove.Dispose();
}
panel.Controls.Clear();

上面代码记得调用Dispose方法来释放控件资源。

在最小的自定义控件中,我们可能需要根据一些条件进行一些自定义绘制处理,以突出显示不同的内容(重点强调选中项目)。

private void NumberItem_Paint(object sender, PaintEventArgs e)

如下是一些特殊的绘制处理内容。

        private void NumberItem_Paint(object sender, PaintEventArgs e)
{
this.BackColor = (this.BorderStyle == BorderStyle.FixedSingle) ? Color.Yellow : Color.Transparent;
if (this.BorderStyle == BorderStyle.FixedSingle)
{
IntPtr hDC = GetWindowDC(this.Handle);
Graphics g = Graphics.FromHdc(hDC);
ControlPaint.DrawBorder(
g,
new Rectangle(0, 0, this.Width, this.Height),
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid,
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid,
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid,
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid);
g.Dispose();
ReleaseDC(Handle, hDC);
}
}

最终展示效果如下所示,黄色强调的处理,是选中相同号码的处理事件结果绘制。

注:本篇随笔借鉴一些特殊的界面来介绍自定义用户控件的处理经验,无其他不良引导,请关注技术本身的分析和处理。

使用Winform开发自定义用户控件,以及实现相关自定义事件的处理的更多相关文章

  1. 在Winform界面使用自定义用户控件及TabelPanel和StackPanel布局控件

    在很多时候,我们做一些非常规化的界面的时候,往往需要创建一些用户控件,在其中绘制好一些基础的界面块,作为后续重复使用的一个单元,用户控件同时也可以封装处理一些简单的逻辑.在开发Winform各种类型项 ...

  2. (九)ASP.NET自定义用户控件(2)

    http://www.cnblogs.com/SkySoot/archive/2012/09/04/2670678.html 用户控件 在 .NET 里,可以通过两种方式把自己的控件插入到 Web 窗 ...

  3. C# WinForm中添加用户控件

    转:https://blog.csdn.net/haelang/article/details/40681003 有的时候我们需要频繁使用一些系统默认工具的组合,那么就可以使用自定义用户控件. 起一个 ...

  4. Windows phone 自定义用户控件(UserControl)——ColorPicker

    编码前 学习Windows phone自定义用户控件,在<WPF编程宝典>学习的小例子.并根据windows phone稍微的不同,做了点修改.ColorPicker(颜色拾取器):拥有三 ...

  5. 2018-8-10-win10-uwp-验证输入-自定义用户控件

    title author date CreateTime categories win10 uwp 验证输入 自定义用户控件 lindexi 2018-08-10 19:16:51 +0800 201 ...

  6. C# winform中自定义用户控件 然后在页面中调用用户控件的事件

    下面是用户控件的代码: using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

  7. C# winform 一个窗体需要调用自定义用户控件的控件名称

    给用户控件ucQRCode增加属性: //二维码图片 private PictureBox _pictureBoxFSHLQrCode; public PictureBox PictureBoxFSH ...

  8. (八)ASP.NET自定义用户控件(1)

    http://blog.csdn.net/laodao1/article/details/5897366 ASP.NET自定义控件组件开发 第一章:从一个简单的控件谈起 起始开发ASP.NET自定义控 ...

  9. 浅尝辄止WPF自定义用户控件(实现颜色调制器)

    主要利用用户控件实现一个自定义的颜色调制控件,实现一个小小的功能,具体实现界面如下. 首先自己新建一个wpf的用户控件类,我就放在我的wpf项目的一个文件夹下面,因为是一个很小的东西,所以就没有用mv ...

  10. C# 自定义用户控件

    上篇:控件制作 本例是制作一个简单的自定义控件,然后用一个简单的测试程序,对于初学者来说,本例子比较简单,只能起到抛石引玉的效果.我也是在学习当中,今后会将自己所学的逐步写出来和大家交流共享. 第一步 ...

随机推荐

  1. 研发三维GIS系统笔记/实现wgs84投影-001

    1. 工作内容,改造引擎,支持wgs84投影 改造原因:目前投影是墨卡托投影(与Google Map一致) 目前的GIS系统是二维的采用这个坐标系是没有问题的 但不支持wgs84瓦片数据以及高程数据, ...

  2. Pricing

    Skip to main content Site Navigation Research Product Developers Safety Company Search   Pricing Sim ...

  3. Gossip in Hyperledger Fabric

    1. Gossip协议基础 1.1 什么是分布式系统 分布式系统(Distributed System)是由多台计算机或计算节点组成的计算机系统,这些计算节点通过网络连接在一起,并协同工作以完成共同的 ...

  4. P8679 [蓝桥杯 2019 省 B] 填空问题 题解

    P8679 [蓝桥杯 2019 省 B] 填空问题 题解 题目传送门 欢迎大家指出错误并联系这个蒟蒻 更新日志 2023-05-25 21:02 文章完成 2023-05-27 11:34 文章通过审 ...

  5. [ABC204E] Rush Hour 2 题解

    Rush Hour 2 题目大意 给定一张无向图,边带两个参数 \(c_i,d_i\),在 \(t\) 时间时经过第 \(i\) 条边所需的时间是 \(c_i+\lfloor\frac{d_i}{t+ ...

  6. select...for update到底是加了行锁,还是表锁?

    前言 前几天,知识星球中的一个小伙伴,问了我一个问题:在MySQL中,事务A中使用select...for update where id=1锁住了,某一条数据,事务还没提交,此时,事务B中去用sel ...

  7. SSH 免秘钥登录

    yum -y install expect ssh-keygen -t rsa -P "" -f /root/.ssh/id_rsa for i in 192.168.1.11 1 ...

  8. MVC(JSP+JavaBean+Servlet)入门实例:用户登陆验证

    一.JSP.JavaBean.Servlet的区别 1.JSP:JSP通过在标准的HTML页面中嵌入Java代码,其静态的部分无效Java程序控制,只有那些需要从数据库读取或需要动态生成的页面内容,才 ...

  9. Redis宕机恢复

    AOF(Append Only File) Redis持久化:AOF日志 用 AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍.如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常 ...

  10. vue3源码学习api-createApp-amount

    vue3 地址 https://github.com/vuejs/core 首先看看vue文档什么是 Vue? ​ Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 Java ...