一 创建窗体库控件
-
创建一个新的Windows Forms Control Library项目,命名为LabelTextbox。
-
单击设计界面,打开控件的属性。把控件的Name属性改为ctLabelTextbox。
-
双击工具箱中的标签,把它添加到用户控件中,放在界面的左上角,把它的Name属性改为lblTextBox,把Text属性设置为Label。
-
双击工具箱中的文本框,把它添加到用户控件中,把它的Name属性改为txtLabelText。
二 编写代码 给标签和文本框定位。
需要添加两个属性,Position:允许用户二选一(Right和Below).TextboxMargin,是一个int,表示控件左边界到文本框的像素数。
1. 添加属性:
Position属性,为了让用户可以选择Right和Below,先用这两个值定义一个枚举类型,返回控件项目,添加代码:
//定义位置选择的两个枚举类型
public enum PositionEnum
{
Right, Below
}
//添加Position字段
private PositionEnum mPosition = PositionEnum.Right;
//添加Position属性
public PositionEnum Position
{
get { return mPosition; }
set
{
mPosition = value;
MoveControls();
}
}
TextboxMargin属性是一样的,但它处理的是一个整数。
//添加TextboxMargin字段
private int mTextboxMargin = 0;
//添加TextboxMargin属性
public int TextboxMargin
{
get { return mTextboxMargin; }
set
{
mTextboxMargin = value;
MoveControls();
}
}
2. 添加事件处理。
可以看到函数已经添加进来了。
添加Load函数处理
//初始化控件和该控件的所有资源
private void ctLabelTextbox_Load(object sender, EventArgs e)
{
lblTextBox.Text = this.Name;//设置label显示的文字
//设置控件高度
this.Height = txtLabelText.Height > lblTextBox.Height ? txtLabelText.Height : lblTextBox.Height;
MoveControls();//移动控件
}
添加SizeChanged函数处理
//改变控件大小时,重新绘制控件
private void ctLabelTextbox_SizeChanged(object sender, EventArgs e)
{
MoveControls();
}
//MoveControls函数
private void MoveControls()
{
switch (mPosition)
{
case PositionEnum.Below:
//设置Textbox的顶部在Label的底部
this.txtLabelText.Top = this.lblTextBox.Bottom;
this.txtLabelText.Left = this.lblTextBox.Left;
//修改Textbox的宽度与控件宽度一致
this.txtLabelText.Width = this.Width;
this.Height = txtLabelText.Height + lblTextBox.Height;
break;
case PositionEnum.Right:
//设置textbox的顶部与label一平
txtLabelText.Top = lblTextBox.Top;
//如果margin值为零,将textbox与label紧挨着放
if (mTextboxMargin == 0)
{
int width = this.Width - lblTextBox.Width - 3;
txtLabelText.Left = lblTextBox.Right + 3;
txtLabelText.Width = width;
}
else
{
//如果margin值不为零,将textbox 放置在用户定义的位置
txtLabelText.Left = mTextboxMargin;
txtLabelText.Width = this.Width - mTextboxMargin;
}
this.Height = txtLabelText.Height > lblTextBox.Height ? txtLabelText.Height : lblTextBox.Height;
break;
}
}
三 调试用户控件
1. 新建测试项目
从File菜单中选择Add|New Project对话框中创建一个新的Windows Application项目,命名为LabelTextboxTest。在Solution Explorer中,已打开了两个项目。第一个项目是前面创建的LabelTextbox,以黑体字显示。如果要运行解决方案。调试程序就会把该控件用作启动项目,这将会失败,因为控件不是一个独立的项目。为了更正这个问题,右击项目名LabelTextboxTest,选择Set as Startup Project。再运行解决方案,就会运行Windows应用程序项目,且不会报错。
右键LabelTextboxTest——设为启动项目
2. 使用控件
现在,在工具箱的顶部应有一个选项卡LabelTextBox Components。Visual Studio知道在解决方案中有一个Windows Control Library,在其他项目中也可能使用这个库提供控件。所以双击控件ctLabelTextbox,把它添加到窗体中。(如果没有看到LabelTextBox Components,就重新生成一下解决方案就可以看见了)
双击ctLabelTextbox,将控件添加到界面中。
3. 运行项目
四 扩展控件功能
到现在为止,还不能对这个控件做什么操作,因为它还不能改变标签和文本框的文本。
1. 添加LabelText和TextboxText两个属性。
private string mLabelText = "";
public string LabelText
{
get
{
return mLabelText;
}
set
{
lblTextBox.Text = value;
}
}
private string mTextboxText = "";
public string TextboxText
{
get
{
return mTextboxText;
}
set
{
mTextboxText = value;
txtLabelText.Text = mTextboxText;
MoveControls();
}
}
2. 为txtLabelText文本框添加KeyDown KeyPress和KeyUp事件。
private void txtLabelText_KeyDown(object sender, KeyEventArgs e)
{
OnKeyDown(e);
}
private void txtLabelText_KeyPress(object sender, KeyPressEventArgs e)
{
OnKeyPress(e);
}
private void txtLabelText_KeyUp(object sender, KeyEventArgs e)
{
OnKeyUp(e);
}
3. 添加定制事件处理PositionChanged,当Position属性改变时,引发事件。
(1)创建委托
需要一个合适的委托,用于调用用户赋给事件的方法。委托是由.NET Framework提供的EventHandler委托。
//声明PositionChanged事件,允许用户订阅该事件。
public event System.EventHandler PositionChanged;
(2)赋值事件
用户必须把一个方法赋给事件,以订阅事件。
//添加Position属性
public PositionEnum Position
{
get { return mPosition; }
set
{
mPosition = value;
MoveControls();
if (PositionChanged != null)
{
PositionChanged(this, new EventArgs());
}
}
}
(3)调用用户赋给事件的方法。
private void ctLabelTextbox1_PositionChanged(object sender, EventArgs e)
{
MessageBox.Show("Chnaged");
}
4. 重新生成解决方案,就可以看见控件的新属性及方法。
在LabelTextboxTest窗体上添加一个按钮,双击它,给项目添加按钮Click事件。
private void button1_Click(object sender, EventArgs e)
{
ctLabelTextbox1.Position = ctLabelTextbox1.Position ==
LabelTextBox.ctLabelTextbox.PositionEnum.Right ?
LabelTextBox.ctLabelTextbox.PositionEnum.Below :
LabelTextBox.ctLabelTextbox.PositionEnum.Right;
}
5. 运行程序,便可以改变文本框的位置啦。
点击button1
五 完整代码
控件完整代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace LabelTextBox
{
public partial class ctLabelTextbox : UserControl
{
//定义位置选择的两个枚举类型
public enum PositionEnum
{
Right, Below
}
//添加两个成员字段
private PositionEnum mPosition = PositionEnum.Right;
private int mTextboxMargin = 0;
//声明PositionChanged事件,允许用户订阅该事件。
public event System.EventHandler PositionChanged;
//添加Position属性
public PositionEnum Position
{
get { return mPosition; }
set
{
mPosition = value;
MoveControls();
if (PositionChanged != null)
{
PositionChanged(this, new EventArgs());
}
}
}
//添加TextboxMargin属性
public int TextboxMargin
{
get { return mTextboxMargin; }
set
{
mTextboxMargin = value;
MoveControls();
}
}
private string mLabelText = "";
public string LabelText
{
get
{
return mLabelText;
}
set
{
lblTextBox.Text = value;
}
}
private string mTextboxText = "";
public string TextboxText
{
get
{
return mTextboxText;
}
set
{
mTextboxText = value;
txtLabelText.Text = mTextboxText;
MoveControls();
}
}
public ctLabelTextbox()
{
InitializeComponent();
}
//初始化控件和该控件的所有资源
private void ctLabelTextbox_Load(object sender, EventArgs e)
{
lblTextBox.Text = this.Name;//设置label显示的文字
//设置控件高度
this.Height = txtLabelText.Height > lblTextBox.Height ? txtLabelText.Height : lblTextBox.Height;
MoveControls();//移动控件
}
//改变控件大小时,重新绘制控件
private void ctLabelTextbox_SizeChanged(object sender, EventArgs e)
{
MoveControls();
}
private void MoveControls()
{
switch (mPosition)
{
case PositionEnum.Below:
//设置Textbox的顶部在Label的底部
this.txtLabelText.Top = this.lblTextBox.Bottom;
this.txtLabelText.Left = this.lblTextBox.Left;
//修改Textbox的宽度与控件宽度一致
this.txtLabelText.Width = this.Width;
this.Height = txtLabelText.Height + lblTextBox.Height;
break;
case PositionEnum.Right:
//设置textbox的顶部与label一平
txtLabelText.Top = lblTextBox.Top;
//如果margin值为零,将textbox与label紧挨着放
if (mTextboxMargin == 0)
{
int width = this.Width - lblTextBox.Width - 3;
txtLabelText.Left = lblTextBox.Right + 3;
txtLabelText.Width = width;
}
else
{
//如果margin值不为零,将textbox 放置在用户定义的位置
txtLabelText.Left = mTextboxMargin;
txtLabelText.Width = this.Width - mTextboxMargin;
}
this.Height = txtLabelText.Height > lblTextBox.Height ? txtLabelText.Height : lblTextBox.Height;
break;
}
}
private void txtLabelText_KeyDown(object sender, KeyEventArgs e)
{
OnKeyDown(e);
}
private void txtLabelText_KeyPress(object sender, KeyPressEventArgs e)
{
OnKeyPress(e);
}
private void txtLabelText_KeyUp(object sender, KeyEventArgs e)
{
OnKeyUp(e);
}
}
}
LabelTextboxTest窗体完整代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace LabelTextboxTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ctLabelTextbox1_PositionChanged(object sender, EventArgs e)
{
MessageBox.Show("Chnaged");
}
private void button1_Click(object sender, EventArgs e)
{
ctLabelTextbox1.Position = ctLabelTextbox1.Position ==
LabelTextBox.ctLabelTextbox.PositionEnum.Right ?
LabelTextBox.ctLabelTextbox.PositionEnum.Below :
LabelTextBox.ctLabelTextbox.PositionEnum.Right;
}
}
}