ASP.NET 图片剪辑控件
代码下载: Anders_Web_Controls_v1_2.zip
介绍
在创建一个自定义的ASP.NET控件时有很多不同的方式。用户只需要将控件拖拽到页面上使用即可。控件本身应该是自包含的,包括注册客户端脚本,CSS和图像等。
本文将引导你创建一个自定义的控件,包含脚本,CSS图像等,并告诉你如何为每个控件初始化JavaScript代码。
具体实现
我们要做的第一件事情是创建Web资源。把所有用到的资源(CSS,JS,IMG)按不同的目录存放。然后将每个文件设置为嵌入资源。(右击/属性 在属性对话框选择 嵌入式资源)
下一步是在AssemblyInfo.cs中嵌入资源:
//Cropping logic
[assembly: WebResource("Anders.Web.Controls.js.cropper.js", "text/javascript")]
//Script lib
[assembly: WebResource("Anders.Web.Controls.js.lib.builder.js", "text/javascript")]
[assembly: WebResource("Anders.Web.Controls.js.lib.dragdrop.js", "text/javascript")]
[assembly: WebResource("Anders.Web.Controls.js.lib.effects.js", "text/javascript")]
[assembly: WebResource("Anders.Web.Controls.js.lib.prototype.js", "text/javascript")]
[assembly: WebResource("Anders.Web.Controls.css.cropper.css",
"text/css", PerformSubstitution = true)]
[assembly: WebResource("Anders.Web.Controls.img.marqueeHoriz.gif", "image/gif")]
[assembly: WebResource("Anders.Web.Controls.img.marqueeVert.gif", "image/gif")]
注意在css资源中我们使用了 PerformSubstitution 属性。该属性指示是否在此资源中引用其他Web资源分析url,并替换该资源的完整路径。这里主要是为了处理css中定义的背景图片。
background: transparent url('<%=WebResource(
"Anders.Web.Controls.img.marqueeHoriz.gif")%>') repeat-x 0 0;
下一步是创建一个剪辑控件的类让它继承自CompositeControl。在.NET自定义控件中它是一个可重用的强大的抽象类。
类还继承了IPostBackDataHandler,这样可以注册控件的回发处理控制。
private Image image = new Image();
private HiddenField cropCords = new HiddenField();
private CropAreaCordinates cropArea = new CropAreaCordinates();
protected override void CreateChildControls()
{
EnsureChildControls();
CheckForHandler();
image.ID = "cropImage";
cropCords.ID = "cords";
Controls.Add(cropCords);
Controls.Add(image);
base.CreateChildControls();
}
Image将是控件的主要界面。HiddenField将存储剪裁的坐标,可以使用PostBack回传给控件。
我们需要设置子控件的id,因为这些将不能自动生成。自id将继承父id的前缀。
因为继承了IPostBackDataHandler接口,所以我们的类必须实现LoadPostData方法。
public bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection postCollection)
{
string v = postCollection[postDataKey + "$cords"];
if (!string.IsNullOrEmpty(v))
{
string[] values = v.Split(';');
cropArea.X = int.Parse(values[0]);
cropArea.Y = int.Parse(values[1]);
cropArea.Width = int.Parse(values[2]);
cropArea.Height = int.Parse(values[3]);
//This values are not saved in client hiddenfield,
//we retrive them from viewstate instead
cropArea.MinWidth = MinWidth;
cropArea.MinHeight = MinHeight;
return true;
}
else
return false;
}
在OnPreRender方法中实现客户端脚本和属性的初始化。
protected override void OnPreRender(EventArgs e)
{
if (CropEnabled)
{
InitClientCrop();
InitImages();
float h = (float)CroppedImageHeight / (float)CroppedImageWidth;
IFormatProvider culture = new CultureInfo("en-US", true);
string height = h.ToString(culture);
image.Attributes["onload"] = string.Format("InitCrop(this.id,
{0},{1},{2},{3},{4},{5}, '{6}', {7}, {8}, {9});",
AllowQualityLoss ? 0 : cropArea.MinWidth,
AllowQualityLoss ? 0 : cropArea.MinHeight,
cropArea.X,
cropArea.Y,
cropArea.Width,
cropArea.Height,
cropCords.ClientID,
CaptureKeys.ToString().ToLower(),
MaintainAspectRatio ? 1 : 0,
MaintainAspectRatio ? height : "0"
);
image.ImageUrl = string.Format("{0}?cropCacheId={1}", httpHandlerPath, CacheKey);
cropCords.Value = string.Format("{0};{1};{2};{3}", cropArea.X,
cropArea.Y, cropArea.Width, cropArea.Height);
Page.RegisterRequiresPostBack(this);
}
else
image.Attributes.Remove("onload");
base.OnPreRender(e);
}
首先,我们在InitClientCrop方法中初始化客户端脚本,在InitImages方法中初始化图片并显示。
我们想在一个页面使用控件的多个实例,所以我们必须为每个控件单独初始化脚本。这里使用客户端的onload事件来处理图片元素。onload事件将在web浏览器完成页面加载后载入图片。
脚本资源注册向这样:首先我们获取资源文件的绝对路径。
string protoTypePath = this.Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.js.lib.prototype.js");
然后,我们在页面使用ClientScriptManager类的RegisterClientScriptInclude方法注册。
this.Page.ClientScript.RegisterClientScriptInclude("prototype.js", protoTypePath);
我们还需要在页面注册CSS文件:
if (Page.Header.FindControl("cropCss") == null)
{
HtmlGenericControl cssMetaData = new HtmlGenericControl("link");
cssMetaData.ID = "cropCss";
cssMetaData.Attributes.Add("rel", "stylesheet");
cssMetaData.Attributes.Add("href",
Page.ClientScript.GetWebResourceUrl(typeof(ImageCropper),
"Anders.Web.Controls.css.cropper.css"));
cssMetaData.Attributes.Add("type", "text/css");
cssMetaData.Attributes.Add("media", "screen");
Page.Header.Controls.Add(cssMetaData);
}
既然可以使用一个以上的控件,我们使用FindControl方法检查是否有其他的控件已经注册了css。
在Web.confg中注册 HttpHandler
<add path="CropImage.axd" verb="*"
type="Anders.Web.Controls.ImageCropperHttpHandler" validate="false" />
当ASP.NET 请求具体的路径"cropImage.axd"时, 将实例化type属性中定义的类。
public class ImageCropperHttpHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
string cacheId = context.Request.QueryString["cropCacheId"];
byte[] buffer = context.Cache[cacheId] as byte[];
context.Response.ContentType = "image/jpeg";
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
}
使用HttpHandlers的唯一缺点就是,需要在Web.config中配置。因此,我们添加了一个方法来检测用户是否在Web.config中进行配置。
private void CheckForHandler()
{
if (httpHandlerPath == null)
{
HttpHandlersSection handlerSection =
WebConfigurationManager.GetWebApplicationSection("system.web/httpHandlers")
as HttpHandlersSection;
bool foundHandler = false;
Type type = typeof(ImageCropperHttpHandler);
string handlerName = type.ToString();
string fullHandlerName = type.AssemblyQualifiedName;
foreach (HttpHandlerAction action in handlerSection.Handlers)
if (action.Type == handlerName || action.Type == fullHandlerName)
{
foundHandler = true;
httpHandlerPath = action.Path.StartsWith("~") ?
string.Empty : "~/" + action.Path;
break;
}
if (!foundHandler)
throw new ApplicationException(string.Format("The HttpHandler {0} is" +
" not registered in the web.config", handlerName));
}
}
英文原文链接:http://www.codeproject.com/KB/custom-controls/ImageCroppingControl.aspx