ASP.NET 颜色选择器 Web 服务器控件






4.85/5 (32投票s)
一个 ASP.NET 颜色选择器 web 服务器控件

引言
很难找到一个像样的 ASP.NET 颜色选择器控件。然而,有很多纯 JavaScript 颜色选择器控件。我决定从中选择一个,并将其转换为 ASP.NET Web 服务器控件。作为基础,我选择了dhtmlgoodies 高级颜色选择器。
项目设置
首先,我们来执行“新建项目 -> ASP.NET 服务器控件”。 默认情况下,项目的名称将与默认命名空间的名称相同。 我将我的项目命名为 WebControls
,并将 ServerControl1.cs 重命名为 ColorPicker.cs。 我将默认命名空间更改为 Karpach.WebControls
,以及程序集名称。 然后,我将 dhtmlgoodies 提供的图像、JavaScript 和样式添加到项目中。

然后,我点击了每个文件的属性,并将“生成操作”从“内容”更改为“嵌入的资源”。 我还重命名了一些文件。
AssemblyInfo.cs
我像这样注册了所有资源
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.SliderHandle.gif",
"img/gif")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.TabCenterActive.gif",
"img/gif")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.TabLeftActive.gif",
"img/gif")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.TabLeftInactive.gif",
"img/gif")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.TabRightActive.gif",
"img/gif")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.TabRightInactive.gif",
"img/gif")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Images.ColorPickerIcon.jpg",
"img/jpeg")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Styles.ColorPicker.css",
"text/css")]
[assembly: System.Web.UI.WebResource("Karpach.WebControls.Javascript.ColorPicker.js",
"text/js")]
您可能已经注意到,System.Web.UI.WebResource
,第一个参数具有以下签名
[Assembly Name].[Folder].[File Name]
这非常重要,因为它甚至没有在 MSDN 中记录。
ColorPicker.cs
为了为您的控件启用验证器,您需要指定您的服务器控件类的 ValidationProperty
属性。
[DefaultProperty("Color"),ValidationProperty("Color")]
我修改了 ToolboxData
使其看起来像这样
[ToolboxData("<{0}:ColorPicker runat="server">")]
接下来,我需要 Visual Studio 工具箱中的自定义图标。 在 ToolboxData
之后,我添加了以下行
[System.Drawing.ToolboxBitmap(typeof(ColorPicker),"Images.color_picker_icon.jpg")]
其中第一个参数是控件的类型,第二个参数是在 AssemblyInfo.cs 中使用的图标文件名。
最初的颜色选择器有两个 JavaScript 文件:color_functions.js 和 js_color_picker_v2.js。 我将它们合并到一个文件中,即 ColorPicker.js。 这些文件包含一堆函数。 我将所有内容合并到一个 JavaScript 类中,公开了一些 public
属性和一个 public
函数 ShowColorPicker
。
function ColorPicker(options)
{
// Public properties
this.FormWidgetAmountSliderHandleImage = options.FormWidgetAmountSliderHandleImage;
this.TabRightActiveImage = options.TabRightActiveImage;
this.TabRightInactiveImage = options.TabRightInactiveImage;
this.TabLeftActiveImage = options.TabLeftActiveImage;
this.TabLeftInactiveImage = options.TabLeftInactiveImage;
this.AutoPostBack = options.AutoPostBack;
this.AutoPostBackReference = options.AutoPostBackReference;
this.PopupPosition = options.PopupPosition;
// Public methods
this.ShowColorPicker = function(inputObj, formField)
{
//.....
}
// Private variables
// ....
// Private functions
// ....
}
在收到一些反馈后,我不得不修复 JavaScript 以支持 ASP.NET AJAX UpdatePanel
和 ModalPopup
扩展器。
然后,我需要从 DLL 中加载存储的资源到 JavaScript 类中。 最佳事件是 OnPreRender
// Javascript
string colorFunctions = Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Javascript.ColorPicker.js");
Page.ClientScript.RegisterClientScriptInclude("ColorPicker.js", colorFunctions);
// Create ColorPicker object
string script = string.Format(@"
var colorPicker_{0} = new ColorPicker({{
FormWidgetAmountSliderHandleImage : '{1}',
TabRightActiveImage : '{2}',
TabRightInactiveImage : '{3}',
TabLeftActiveImage : '{4}',
TabLeftInactiveImage : '{5}',
AutoPostBack : {6},
AutoPostBackReference : ""{7}"",
PopupPosition : {8}
}});
", ClientID
, Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Images.SliderHandle.gif")
, Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Images.TabRightActive.gif")
, Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Images.TabRightInactive.gif")
, Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Images.TabLeftActive.gif")
, Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Images.TabLeftInactive.gif")
, AutoPostBack?"true":"false"
, Page.ClientScript.GetPostBackEventReference(this,"")
, (int)PopupPosition
);
Page.ClientScript.RegisterStartupScript(Page.GetType(),
String.Format("InitColorPicker_{0}", ClientID), script, true);
if (!DesignMode && Page.Header != null)
{
RegisterCSSInclude(Page.Header);
}
其中 RegisterCSSInclude
是以下辅助方法
private void RegisterCSSInclude(Control target)
{
// CSS
bool linkIncluded = false;
foreach (Control c in target.Controls)
{
if (c.ID == "ControlPickerStyle")
{
linkIncluded = true;
}
}
if (!linkIncluded)
{
HtmlGenericControl csslink = new HtmlGenericControl("link");
csslink.ID = "ControlPickerStyle";
csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl
(typeof(ColorPicker), "Karpach.WebControls.Styles.ColorPicker.css"));
csslink.Attributes.Add("type", "text/css");
csslink.Attributes.Add("rel", "stylesheet");
csslink.EnableViewState = false;
target.Controls.Add(csslink);
}
}
然后我重写了 WebControl
类的 Render
事件,以渲染控件 HTML。
using (PlaceHolder plh = new PlaceHolder())
{
if (DesignMode || Page.Header == null)
RegisterCSSInclude(plh);
Table table = new Table();
table.CellPadding = 0;
table.CellSpacing = 0;
table.Rows.Add(new TableRow());
table.Rows[0].Cells.Add(new TableCell());
table.Rows[0].Cells.Add(new TableCell());
table.Rows[0].Cells.Add(new TableCell());
table.Rows[0].Cells[1].Style.Add(HtmlTextWriterStyle.PaddingRight, "5px");
HtmlGenericControl txt = new HtmlGenericControl("input");
txt.EnableViewState = false;
txt.Attributes.Add("maxlength", "15");
txt.Attributes.Add("size", "15");
txt.Attributes.Add("value", Color);
txt.Attributes.Add("id", ClientID);
txt.Attributes.Add("name", UniqueID);
txt.Attributes.CssStyle.Value = "height:17px;padding:2px;";
table.Rows[0].Cells[0].Controls.Add(txt);
HtmlGenericControl colorBar = new HtmlGenericControl("div");
colorBar.EnableViewState = false;
colorBar.Attributes.CssStyle.Add(HtmlTextWriterStyle.Height, "21px");
colorBar.Attributes.CssStyle.Add(HtmlTextWriterStyle.Width, "5px");
colorBar.Attributes.CssStyle.Add("border", "solid 1px #7f9db9");
colorBar.Attributes.CssStyle.Add(HtmlTextWriterStyle.BackgroundColor, Color);
table.Rows[0].Cells[1].Controls.Add(colorBar);
HtmlInputImage btn = new HtmlInputImage();
btn.Src = Page.ClientScript.GetWebResourceUrl(typeof(ColorPicker),
"Karpach.WebControls.Images.ColorPickerIcon.jpg");
btn.Attributes.Add("onclick", string.Format("colorPicker_{0}.ShowColorPicker
(this,document.getElementById('{1}'));return false;", ClientID, ClientID));
btn.Attributes.CssStyle.Add(HtmlTextWriterStyle.ZIndex, "1");
HtmlGenericControl container = new HtmlGenericControl("div");
container.EnableViewState = false;
container.Controls.Add(btn);
container.Attributes.CssStyle.Add(HtmlTextWriterStyle.Position, "static");
container.Attributes.CssStyle.Add(HtmlTextWriterStyle.Display, "block");
table.Rows[0].Cells[2].Controls.Add(container);
plh.Controls.Add(table);
plh.RenderControl(output);
}
您可以通过几种方式保存颜色选择器的回发值。 但是我认为最好的方法是实现 IPostBackDataHandler
接口。
public bool LoadPostData(string postDataKey,NameValueCollection postCollection)
{
String presentValue = Color;
String postedValue = postCollection[postDataKey];
if (presentValue == null || !presentValue.Equals(postedValue))
{
Color = postedValue;
return true;
}
return false;
}
public virtual void RaisePostDataChangedEvent()
{
OnColorChanged(EventArgs.Empty);
}
public void OnColorChanged(EventArgs e)
{
if (ColorChanged != null)
ColorChanged(this, e);
}
LoadPostData
方法将在每次回发期间被调用,当回发表单具有键为 this.UniqueID
的令牌时。 如您所见,渲染的 input 标签具有 name 属性 this.UniqueID
。
ColorPicker
属性通过重写 LoadControlState
和 SaveControlState
存储在 ControlState
中
protected override void LoadControlState(object savedState)
{
Color = (string)(savedState as object[])[0];
AutoPostBack = (bool)(savedState as object[])[1];
PopupPosition = (PopupPosition)(savedState as object[])[2];
}
protected override object SaveControlState()
{
object []saveState = new object[3];
saveState[0] = Color;
saveState[1] = AutoPostBack;
saveState[2] = PopupPosition;
return (object)saveState;
}
您需要调用 RegisterRequiresControlState
方法来注册控件以参与控件状态,否则 LoadControlState
和 SaveControlState
将不会触发。
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.RegisterRequiresControlState(this);
}
Build.proj
现在,最后的润色:JavaScript 和 CSS 的最小化。 我使用了 Yahoo YUI 压缩器和 Microsoft MSBuild。 这是最终的 MSbuild 文件
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildCommunityTasksPath>..\References</MSBuildCommunityTasksPath>
<ProjectName>WebControls</ProjectName>
</PropertyGroup>
<Target Name="Compress">
<Message Text="Create temp files ..." />
<Copy SourceFiles=".\$(ProjectName)\Javascript\ColorPicker.js"
DestinationFiles=".\$(ProjectName)\Javascript\ColorPicker.js.full"/>
<Copy SourceFiles=".\$(ProjectName)\Styles\ColorPicker.css"
DestinationFiles=".\$(ProjectName)\Styles\ColorPicker.css.full"/>
<Exec Command=
"java -jar yuicompressor-2.4.2.jar --type js .\$(ProjectName)\
Javascript\ColorPicker.js.full >.\$(ProjectName)\Javascript\ColorPicker.js"/>
<Exec Command=
"java -jar yuicompressor-2.4.2.jar --type css .\$(ProjectName)\Styles\
ColorPicker.css.full >.\$(ProjectName)\Styles\ColorPicker.css"/>
</Target>
<Import Project=".\References\MSBuild.Community.Tasks.targets" />
<Target Name="Build" DependsOnTargets="Compress">
<Message Text="Building Project" />
<MSBuild Projects="./$(ProjectName)/$(ProjectName).sln"
Properties="Configuration=Release;Platform=Any CPU" />
</Target>
</Project>
现在您甚至不需要 Visual Studio 来编译 DLL。 您所需要的只是安装了 .NET 2.0,然后以下控制台脚本将完成编译
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe Build.proj /t:Build
根据下面的请求,我添加了 PopupPosition
属性,因此您可以指定 ColorPicker
弹窗的位置(左上、右上、左下、右下 - 默认)。
我还添加了 AutoPostBack
属性和 ColorChanged
事件。