65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (32投票s)

2008年7月20日

CPOL

3分钟阅读

viewsIcon

277063

downloadIcon

3044

一个 ASP.NET 颜色选择器 web 服务器控件

ColorPickerDemo.png

引言

很难找到一个像样的 ASP.NET 颜色选择器控件。然而,有很多纯 JavaScript 颜色选择器控件。我决定从中选择一个,并将其转换为 ASP.NET Web 服务器控件。作为基础,我选择了dhtmlgoodies 高级颜色选择器

项目设置

首先,我们来执行“新建项目 -> ASP.NET 服务器控件”。 默认情况下,项目的名称将与默认命名空间的名称相同。 我将我的项目命名为 WebControls,并将 ServerControl1.cs 重命名为 ColorPicker.cs。 我将默认命名空间更改为 Karpach.WebControls,以及程序集名称。 然后,我将 dhtmlgoodies 提供的图像、JavaScript 和样式添加到项目中。

CustomControlSolutionFiles.gif

然后,我点击了每个文件的属性,并将“生成操作”从“内容”更改为“嵌入的资源”。 我还重命名了一些文件。

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.jsjs_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 UpdatePanelModalPopup 扩展器。

然后,我需要从 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 属性通过重写 LoadControlStateSaveControlState 存储在 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 方法来注册控件以参与控件状态,否则 LoadControlStateSaveControlState 将不会触发。

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 事件。

© . All rights reserved.