ASP.NET自定义控件开发--微调控件(NumericUpDown)
效果图如右:
先总结一下开发中的问题和经验:
1.注意:将控件项目的“属性”-->“通用属性”-->“常规”中的“默认命名空间”设为空,否则总出现错误:“System.ArgumentException: 已存在具有相同键的条目。”
哪位高手知道原因的话请赐教。???
2.注意:将.js文件和.bmp文件作为嵌入资源进行编译。方法:在“解决方案资源管理器”中选中文件,右键“属性”,在属性框中“生成操作”项中选择“嵌入的资源”,随后编译该项目即可。
3.注意:.bmp文件是作为控件的自定义图标显示在工具箱中的(如果你把控件添加到工具箱中的话),该文件要求必须与控件同名(如本程序中的命名为:Xct.WebControls.Spinner.bmp),且带.bmp后缀。
4.将控件添加到工具箱中的方法:VS2003-IDE菜单“工具”-->“添加/移除工具箱项...”,在“.NET Framework组件”选项卡中点击“浏览”,选择控件对应的dll文件后点击“确定”。在工具箱的“常规”选项卡中就出现新添的控件,如图

5.优点:该控件在编译时将JS脚本资源嵌入到了程序集dll文件中,使得在布暑应用时不需要再拷贝js文件。
6.问题:该控件的属性“TextAlign - 文本对齐方式”不起作用,不知怎么回事。???
运行环境:Win2003Server + IIS6 + VS2003 + .NET Framework 1.1 + IE6
附:《ASP.NET组件工具包》书中的代码可以在http://support.apress.com/books.asp?bID=1861008023&s=0下载.(注:在www.wrox.com找不到其源码下载)
===============================================================================
控件程序代码(Spinner.cs):----
using System;2
using System.Web.UI;3
using System.Web.UI.WebControls;4
using System.ComponentModel;5
using System.IO;6

7

8
//指定控件的标记前缀9
[assembly: TagPrefix("Xct.WebControls","xct")]10
namespace Xct.WebControls11
{12
#region 枚举类型13
/// <summary>14
/// 滚动箭头的位置,可以在文本框左侧或右侧15
/// </summary>16
public enum SpinnerAlign17
{18
Left = 0,19
Right = 120
}21

22
/// <summary>23
/// 文本框中的文本对齐方式24
/// </summary>25
public enum ValueAlign26
{27
Center = 0,28
Left = 1,29
Right = 230
}31
#endregion32

33
/// <summary>34
/// ** 微调控件V1.0 ** (夏春涛 2007-09-26) **35
/// </summary>36
37
[ToolboxData("<{0}:Spinner runat=\"server\" width=\"80px\" buttonsize=\"XX-Small\" />")]38
public class Spinner : WebControl, INamingContainer39
{40
#region 脚本资源变量41
//Scripts变量用于存储脚本资源42
private static string Scripts;43
//StartupScriptFormat变量用于存储初始化微调控件的脚本资源44
private static string StartupScriptFormat = "<script language=\"JavaScript\">t = document.getElementById(\"{0}\"); t.step = {1}; t.original = {2}; t.max = {3}; t.min = {4};</script>";45
#endregion46

47
#region 静态构造函数48
/// <summary>49
/// 静态构造函数,从程序集中提取脚本资源字符串,并将之存入Scripts变量50
/// </summary>51
static Spinner()52
{53
//获取当前代码正从中运行的 System.Reflection.Assembly54
System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();55

56
if (asm != null)57
{58
string resource = "SpinnerLib.js";59
Stream stm = asm.GetManifestResourceStream(resource);//从程序集加载指定的清单资源60
if (stm==null) return;61

62
try63
{64
StreamReader reader = new StreamReader(stm);65
Scripts = reader.ReadToEnd();66
reader.Close();67
}68
finally69
{70
if (stm != null) stm.Close();71
}72

73
}74
}75
#endregion76

77
#region 属性定义78
79
#region Increment - 步长80
private int _inc = 1;81

82
[Bindable(true),Category("Data"),DefaultValue(1),Description("步长")]83
public int Increment84
{85
get86
{87
return _inc;88
}89

90
set91
{92
_inc = value;93
}94
}95
#endregion96

97
#region Value - 值98
private int _value = 0;99

100
[Bindable(true),Category("Appearance"),DefaultValue(0),Description("值")]101
public int Value102
{103
get104
{105
return _value;106
}107

108
set109
{110
_value = value;111
base.ChildControlsCreated = false; 112
}113
}114
#endregion115

116
#region Maximum - 最大值117
private int _max = 100;118

119
[Bindable(true),Category("Data"),DefaultValue(100),Description("最大值")]120
public int Maximum121
{122
get123
{124
return _max;125
}126

127
set128
{129
_max = value;130
}131
}132
#endregion133
134
#region Minimum - 最小值135
private int _min = 0;136

137
[Bindable(true),Category("Data"),DefaultValue(0),Description("最小值")]138
public int Minimum139
{140
get141
{142
return _min;143
}144

145
set146
{147
_min = value;148
}149
}150
#endregion151

152
#region ButtonAlign - 按钮位置153
private SpinnerAlign _align = SpinnerAlign.Right;154

155
[Bindable(true),Category("Layout"),DefaultValue(SpinnerAlign.Right),Description("按钮位置")]156
public SpinnerAlign ButtonAlign157
{158
get159
{160
return _align;161
}162

163
set164
{165
if (!Enum.IsDefined(Type.GetType("Xct.WebControls.SpinnerAlign"),value))166
throw new ArgumentException();167

168
//将基类的ChildControlsCreated设为false,为此需要重写ChildControlsCreated方法,169
//该方法用于构建组成界面的子控件的层次结构170
base.ChildControlsCreated = false;171
_align = value;172
}173
}174
#endregion175

176
#region TextAlign - 文本对齐方式177
private ValueAlign _textalign = ValueAlign.Right;178

179
[Bindable(true),Category("Layout"),DefaultValue(ValueAlign.Right),Description("文本对齐方式")]180
public ValueAlign TextAlign181
{182
get183
{184
return _textalign;185
}186

187
set188
{189
if (!Enum.IsDefined(Type.GetType("Xct.WebControls.ValueAlign"),value))190
throw new ArgumentException();191

192
//将基类的ChildControlsCreated设为false,为此需要重写ChildControlsCreated方法,193
//该方法用于构建组成界面的子控件的层次结构194
base.ChildControlsCreated = false;195
_textalign = value;196
}197
}198
#endregion199

200
#region ButtonSize - 按钮字体大小201
private FontUnit _size;202

203
[Bindable(true),Category("Appearance"),Description("按钮字体大小")]204
public FontUnit ButtonSize205
{206
get207
{208
return _size;209
}210

211
set212
{213
base.ChildControlsCreated = false;214
_size = value;215
}216
}217
#endregion218

219
#endregion220
221
#region 重载ChildControlsCreated方法222
//构建组成界面的子控件的层次结构,以便为回发或呈现做准备223
//当开发复合服务器控件或模板服务器控件时,必须重写此方法224
protected override void CreateChildControls()225
{226
#region 创建表格227
Table tb = new Table();228
TableCell tc;229

230
tb.CellPadding = 0;231
tb.CellSpacing = 0;232

233
tb.Rows.Add(new TableRow());234
tb.Rows.Add(new TableRow());235
tb.Rows[0].Cells.Add(new TableCell());236
tb.Rows[0].Cells.Add(new TableCell());237
tb.Rows[1].Cells.Add(new TableCell());238

239
base.Controls.Clear();//清除基类中的控件240
base.Controls.Add(tb);//添加新创建的表格241
#endregion242

243
#region 创建文本框244
TextBox txt = new TextBox();245
txt.ID = "txtValue";246
//通过Attributes集合把客户端JS事件处理程序添加到服务器控件247
txt.Attributes.Add("OnKeyPress","return KeyPressed(event,this)");248
txt.Attributes.Add("OnKeyUp", "return KeyUp(this)");249
txt.Attributes.Add("OnChange", "return SpinnerChanged(this)");250
txt.Attributes.Add("OnPaste", "return SpinnerChanged(this)");251
//应用样式252
txt.ApplyStyle(this.ControlStyle);253
//移除文本框的Border(用表格单元格Border代替)254
txt.Style.Add("Border-Top", "none");255
txt.Style.Add("Border-Right", "none");256
txt.Style.Add("Border-Left", "none");257
txt.Style.Add("Border-Bottom","none");258
txt.Width = new Unit("100%"); //文本框的宽度259
txt.Text = this.Value.ToString(); //文本框的值260
261

262
//设置文本框所在的单元格的样式263
if (this.ButtonAlign == SpinnerAlign.Left)264
tc = tb.Rows[0].Cells[1];265
else266
tc = tb.Rows[0].Cells[0];267

268
tc.Style.Add("vertical-align","middle");269

270
tc.ApplyStyle(this.ControlStyle);271

272
tc.Style.Add("Border-Top", "2px inset");273
tc.Style.Add("Border-Right", "silver 1px solid");274
tc.Style.Add("Border-Left", "2px inset");275
tc.Style.Add("Border-Bottom","silver 1px solid");276
tc.Controls.Add(txt);277
tc.RowSpan = 2;//使文本框跨越Up/Down按钮两行278
tc.Width = new Unit("100%");279
#endregion280

281
#region Up按钮282
//判断客户端浏览器是不是IE283
bool isIE = true;284
try285
{286
isIE = Context.Request.Browser.VBScript;287
}288
catch289
{290
//null291
}292

293
//Up按钮的单元格294
if (this.ButtonAlign == SpinnerAlign.Left)295
tc = tb.Rows[0].Cells[0];296
else297
tc = tb.Rows[0].Cells[1];298

299
//Up按钮300
tc.BackColor = System.Drawing.Color.Gainsboro;301
tc.BorderStyle = (isIE==true ? BorderStyle.Outset : BorderStyle.Solid);302
tc.BorderWidth = new Unit("1px");303
tc.Style.Add("cursor", "pointer");304
tc.Font.Size = _size;305

306
tc.Attributes.Add("OnMouseUp", "this.style.backgroundColor='Gainsboro';" + (isIE==true ? "this.style.borderStyle='outset';" : ""));307
tc.Attributes.Add("OnMouseDown", "this.style.backgroundColor='WhiteSmoke';" + (isIE==true ? "this.style.borderStyle='inset';" : ""));308
tc.Attributes.Add("OnMouseOut", "this.style.backgroundColor='Gainsboro';" + (isIE==true ? "this.style.borderStyle='outset';" : ""));309
tc.Attributes.Add("OnClick", "Increment('" + txt.ClientID + "');");310
tc.Text = "▲";//字符"▲".311
#endregion312

313
#region Down按钮314
tc = tb.Rows[1].Cells[0];315
tc.BackColor = System.Drawing.Color.Gainsboro;316
tc.BorderStyle = (isIE==true ? BorderStyle.Outset : BorderStyle.Solid);317
tc.BorderWidth = new Unit("1px");318
tc.Style.Add("cursor", "pointer");319
tc.Font.Size = _size;320

321
tc.Attributes.Add("OnMouseUp", "this.style.backgroundColor='Gainsboro';" + (isIE==true ? "this.style.borderStyle='outset';" : ""));322
tc.Attributes.Add("OnMouseDown", "this.style.backgroundColor='WhiteSmoke';" + (isIE==true ? "this.style.borderStyle='inset';" : ""));323
tc.Attributes.Add("OnMouseOut", "this.style.backgroundColor='Gainsboro';" + (isIE==true ? "this.style.borderStyle='outset';" : ""));324
tc.Attributes.Add("OnClick", "Decrement('" + txt.ClientID + "');");325

326
tc.Text = "▼";//字符"▼"327
#endregion328

329
}330

331
#endregion332

333
#region 重载AddAttributesToRender334
//将需要呈现的 HTML 属性和样式添加到指定的 HtmlTextWriterTag 中。此方法主要由控件开发人员使用335
protected override void AddAttributesToRender(HtmlTextWriter writer)336
{337
//请注意TextBox控件的宽度被指定为100%,所以如果省略下步控件的宽度会覆盖整个页面338
writer.AddStyleAttribute(HtmlTextWriterStyle.Width,this.Width.ToString());//默认宽度80px339
}340
#endregion341

342
#region 重载OnPreRender343
//此方法通知服务器控件在保存视图状态和呈现内容之前,执行任何必要的预呈现步骤344
protected override void OnPreRender(EventArgs e)345
{346
EnsureChildControls();//确定服务器控件是否包含子控件。如果不包含,则创建子控件。347
base.OnPreRender (e);348
}349
#endregion350

351
#region 重载Render352
//将服务器控件内容发送到提供的 HtmlTextWriter 对象,此对象编写将在客户端呈现的内容353
//在开发自定义服务器控件时,可以重写此方法以生成 ASP.NET 页的内容354
protected override void Render(HtmlTextWriter writer)355
{356
EnsureChildControls();//确定服务器控件是否包含子控件。如果不包含,则创建子控件。357
base.Render(writer);358
}359
#endregion360

361
#region 重载OnLoad,向客户端发送JS脚本资源362
protected override void OnLoad(EventArgs e)363
{364
EnsureChildControls();//确定服务器控件是否包含子控件。如果不包含,则创建子控件。365
366
367
//注册脚本库368
if (!Page.IsClientScriptBlockRegistered(this.GetType().FullName))369
{370
Page.RegisterClientScriptBlock(this.GetType().FullName, Scripts);371
}372

373
Page.RegisterStartupScript(this.ClientID, String.Format( StartupScriptFormat, 374
this.FindControl("txtValue").ClientID, 375
this.Increment, 376
this.Value, 377
this.Maximum, 378
this.Minimum379
)380
);381

382
base.OnLoad (e);383
}384
#endregion385

386

387
}388
}389

Javascript脚本源码(SpinnerLib.js, 这是原书附带的代码):----
<script language="JavaScript">2
<!--3
function IsChar(code)4
{5
return /\w/.test(String.fromCharCode(code));6
}7
function KeyPressed(e, src)8
{9
var code;10

11
if (e.which == undefined)12
{13
//IE14
code = e.keyCode;15
}16
else17
{18
//Mozilla/NS6+19
code = e.which;20
}21

22
// It's not a character value, leave the function.23
if (!IsChar(code)) return true;24
25
return !isNaN(String.fromCharCode(code));26
}27
function KeyUp(src)28
{29
// If we have a valid value, we save it for later,30
// else we restore the previously saved value.31
if (src.value <= src.max && src.value >= src.min)32
{33
src.original = src.value;34
return true;35
}36
else37
{38
// Exceptional case: the user is entering a negative number.39
if (src.value == "-") return true;40

41
src.value = src.original;42
return false;43
}44
}45
function SpinnerChanged(src)46
{47
// If we have a valid value, we save it for later,48
// else we restore the previously saved value.49
if (src.value <= src.max && src.value >= src.min)50
{51
src.original = src.value;52
return true;53
}54
else55
{56
src.value = src.original;57
return false;58
}59
}60

61
function Decrement(target)62
{63
src = document.getElementById(target);64
src.value = parseInt(src.value) - parseInt(src.step);65
SpinnerChanged(src);66
src.focus();67
}68

69
function Increment(target)70
{71
src = document.getElementById(target);72
src.value = parseInt(src.value) + parseInt(src.step);73
SpinnerChanged(src);74
src.focus();75
}76
//-->77
</script>




浙公网安备 33010602011771号