【概述】几乎每个企业都有自己的核心东西或说是框架性的东西,框架的好处是将我们经常要使用的功能,控件等包装一个个
易于使用的单元,就算是初学者也极其容易上手,减少项目的开发成本。因此框架的重要性和好处是不言而喻的。在我的这个系列
(一点一滴打造我们自己的web开发框架系列 )当中,我将自己在开发过程中用到的一些东西陆续公布出来,和大家一起交流学习。
这次我们接着上次我们开发的客户端web页面上的右键菜单(参看我上一篇文章:一点一滴打造我们自己的web开发框架系列【web右键菜单的开发(上)】 ),我们将它包装成服务器控件方便使用,毕竟我们大多数人还是习惯从工具栏直接拖拽出来使用,而不是写n多js代码。
Web右键菜单服务器控件(WebContextMenu)开发的需求分析:
1,我们需要一个菜单项的类(WebContextMenuItem)。
2,其次在我们即将要实现的WebContextMenu中,我们肯定需要一个菜单项的集合对吧,不然怎么存放每个菜单项呢,因此需要一个菜单项的集合类(WebContextMenuItemCollection)。
3,当然最后我们是实现WebContextMenu控件类。
4,还要包含昨天我们用过的菜单的客户端脚本WebContextMenu.js及jquery.js。
截个图大家看看控件的目录结构:
接下来,我们一个文件去实现,当然WebContextMenu.js昨天已经写好了,jquery.js包含进去就Ok了,注意一定要设为嵌入的资源,
WebContextMenuItem的实现:
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ProjectSample.WebControls
{
[ToolboxItem(false)]
public sealed class WebContextMenuItem : WebControl, INamingContainer, IStateManager
{
private string text;
private string img;
private string handler;
private bool marked;
private bool textIsdirty;
private bool imgIsdirty;
private bool handlerIsdirty;
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
public string Text
{
get { return this.text; }
set { this.text = value; }
}
public string Image
{
get { return this.img; }
set { this.img = value; }
}
public string Handler
{
get { return this.handler; }
set { this.handler = value; }
}
public WebContextMenuItem()
{ }
public WebContextMenuItem(string text, string img, string handler)
{
this.text = text;
this.img = img;
this.handler = handler;
}
internal bool Dirty
{
get
{
if (!this.textIsdirty && !this.imgIsdirty)
{
return this.handlerIsdirty;
}
return true;
}
set
{
this.textIsdirty = value;
this.imgIsdirty = value;
this.handlerIsdirty = value;
}
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
bool IStateManager.IsTrackingViewState
{
get
{
return this.marked;
}
}
internal void TrackViewState()
{
this.marked = true;
}
internal object SaveViewState()
{
string x = null;
string y = null;
if (this.textIsdirty)
{
x = this.Text;
}
if (this.imgIsdirty)
{
y = this.Image;
}
if (this.handlerIsdirty)
{
return new Triplet(x, y, this.Handler);
}
if (this.imgIsdirty)
{
return new Pair(x, y);
}
if (this.textIsdirty)
{
return x;
}
return null;
}
internal void LoadViewState(object state)
{
if (state != null)
{
if (state is Triplet)
{
Triplet triplet = (Triplet)state;
if (triplet.First != null)
{
this.Text = (string)triplet.First;
}
if (triplet.Second != null)
{
this.Image = (string)triplet.Second;
}
if (triplet.Third != null)
{
try
{
this.Handler = (string)triplet.Third;
}
catch
{
}
}
}
else if (state is Pair)
{
Pair pair = (Pair)state;
if (pair.First != null)
{
this.Text = (string)pair.First;
}
this.Image = (string)pair.Second;
}
else
{
this.Text = (string)state;
}
}
}
}
}
因为我们需要将WebContextMenuItem做为菜单的子控件,所以让他从WebControl继承,同时我们需要他在页面回传后能够通过视图状态保存原来我们设定的每个菜单项目,所以让他继承了IStateManager接口。
接下来,我们实现WebContextMenuItemCollection,菜单的集合类同样需要继承IStateManager接口,并且需要实现ICollection, IList的一些操作,方便我们在前台页面的.cs代码中来操作菜单。
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace ProjectSample.WebControls
{
[ToolboxItem(false)]
public class WebContextMenuItemCollection : ICollection, IList, IStateManager
{
private ArrayList listItems = new ArrayList();
private bool marked = false;
private bool saveAll = false;
public bool IsReadOnly
{
get
{
return this.listItems.IsReadOnly;
}
}
public void Remove(WebContextMenuItem item)
{
int index = this.IndexOf(item);
if (index >= 0)
{
this.RemoveAt(index);
}
}
public void RemoveAt(int index)
{
this.listItems.RemoveAt(index);
if (this.marked)
{
this.saveAll = true;
}
}
public void Add(WebContextMenuItem item)
{
this.listItems.Add(item);
if (this.marked)
{
item.Dirty = true;
}
}
public void AddRange(WebContextMenuItem[] items)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
for (int i = 0; i <items.Length; i++)
{
WebContextMenuItem menuItem = (WebContextMenuItem)items[i];
this.Add(menuItem);
}
}
bool IList.Contains(object item)
{
return this.Contains((WebContextMenuItem)item);
}
public int IndexOf(WebContextMenuItem item)
{
return this.listItems.IndexOf(item);
}
public void Insert(int index, WebContextMenuItem item)
{
this.listItems.Insert(index, item);
if (this.marked)
{
this.saveAll = true;
}
}
int IList.Add(object item)
{
WebContextMenuItem item2 = (WebContextMenuItem)item;
int num = this.listItems.Add(item2);
if (this.marked)
{
item2.Dirty = true;
}
return num;
}
int IList.IndexOf(object item)
{
return this.IndexOf((WebContextMenuItem)item);
}
void IList.Insert(int index, object item)
{
this.Insert(index, (WebContextMenuItem)item);
}
void IList.Remove(object item)
{
this.Remove((WebContextMenuItem)item);
}
public int Capacity
{
get
{
return this.listItems.Capacity;
}
set
{
this.listItems.Capacity = value;
}
}
public int Count
{
get
{
return this.listItems.Count;
}
}
public bool IsSynchronized
{
get
{
return this.listItems.IsSynchronized;
}
}
public object SyncRoot
{
get
{
return this;
}
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
object IList.this[int index]
{
get
{
return this.listItems[index];
}
set
{
this.listItems[index] = (ListItem)value;
}
}
public void Clear()
{
this.listItems.Clear();
}
public bool Contains(WebContextMenuItem item)
{
return this.listItems.Contains(item);
}
public void CopyTo(Array array, int index)
{
this.listItems.CopyTo(array, index);
}
public IEnumerator GetEnumerator()
{
return this.listItems.GetEnumerator();
}
public WebContextMenuItem this[int index]
{
get
{
return (WebContextMenuItem)this.listItems[index];
}
}
bool IStateManager.IsTrackingViewState
{
get
{
return this.marked;
}
}
void IStateManager.LoadViewState(object state)
{
this.LoadViewState(state);
}
object IStateManager.SaveViewState()
{
return this.SaveViewState();
}
void IStateManager.TrackViewState()
{
this.TrackViewState();
}
internal object SaveViewState()
{
if (this.saveAll)
{
int count = this.Count;
object[] objArray = new string[count];
object[] objArray2 = new string[count];
object[] z = new string[count];
for (int j = 0; j < count; j++)
{
objArray[j] = this[j].Text;
objArray2[j] = this[j].Image;
z[j] = this[j].Handler;
}
return new Triplet(objArray, objArray2, z);
}
ArrayList x = new ArrayList(4);
ArrayList y = new ArrayList(4);
for (int i = 0; i < this.Count; i++)
{
object obj2 = this[i].SaveViewState();
if (obj2 != null)
{
x.Add(i);
y.Add(obj2);
}
}
if (x.Count > 0)
{
return new Pair(x, y);
}
return null;
}
internal void LoadViewState(object state)
{
if (state != null)
{
if (state is Pair)
{
Pair pair = (Pair)state;
ArrayList first = (ArrayList)pair.First;
ArrayList second = (ArrayList)pair.Second;
for (int i = 0; i < first.Count; i++)
{
int num2 = (int)first[i];
if (num2 < this.Count)
{
this[num2].LoadViewState(second[i]);
}
else
{
WebContextMenuItem item = new WebContextMenuItem();
item.LoadViewState(second[i]);
this.Add(item);
}
}
}
else
{
Triplet triplet = (Triplet)state;
this.listItems = new ArrayList();
this.saveAll = true;
string[] strArray = (string[])triplet.First;
string[] strArray2 = (string[])triplet.Second;
string[] third = (string[])triplet.Third;
for (int j = 0; j < strArray.Length; j++)
{
this.Add(new WebContextMenuItem(strArray[j], strArray2[j], third[j]));
}
}
}
}
internal void TrackViewState()
{
this.marked = true;
for (int i = 0; i < this.Count; i++)
{
this[i].TrackViewState();
}
}
}
}
最后我们来实现WebContextMenu服务器控件
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
[assembly: WebResource("ProjectSample.WebControls.jquery.js", "text/javascript")]
[assembly: WebResource("ProjectSample.WebControls.WebContextMenu.WebContextMenu.js", "text/javascript")]
namespace ProjectSample.WebControls
{
[ToolboxData("<{0}:WebContextMenu runat=server></{0}:WebContextMenu>")]
[ControlBuilder(typeof(WebContextMenuBuilder))]
[ParseChildren(true, "MenuItems")]
public class WebContextMenu:WebControl
{
#region 菜单集合
private WebContextMenuItemCollection _menuItems;
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public WebContextMenuItemCollection MenuItems
{
get
{
if (_menuItems == null)
{
this._menuItems = new WebContextMenuItemCollection();
if (base.IsTrackingViewState)
this._menuItems.TrackViewState();
}
return this._menuItems;
}
}
#endregion
/// <summary>
/// 关联到客户端控件
/// </summary>
[Bindable(true), Browsable(true), DefaultValue("")]
public string AttachedClientControlId
{
get
{
if (ViewState[this.ID + "_AttachedClientControlId"] != null)
return (string)ViewState[this.ID + "_AttachedClientControlId"];
throw new ArgumentNullException("必须指定要关联的客户端控件Id");
}
set
{
ViewState[this.ID + "_AttachedClientControlId"] = value;
}
}
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
protected override void AddParsedSubObject(object obj)
{
if (obj is WebContextMenuItem)
base.AddParsedSubObject(obj);
}
/// <summary>
/// 呈现菜单
/// </summary>
/// <param name="writer"></param>
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
this.Page.ClientScript.RegisterClientScriptResource(this.GetType(), "ProjectSample.WebControls.jquery.js");
this.Page.ClientScript.RegisterClientScriptResource(this.GetType(), "ProjectSample.WebControls.WebContextMenu.WebContextMenu.js");
StringBuilder script=new StringBuilder();
script.Append("\nvar " + this.UniqueID + " = new WebContextMenu(\"" + this.UniqueID + "\",\"" + this.AttachedClientControlId + "\");\n");
foreach(WebContextMenuItem menuItem in this.MenuItems)
{
script.Append(""+this.UniqueID+".add_MenuItem(new WebContextMenu.MenuItem(\""+menuItem.Text+"\", \""+menuItem.Image+"\", \""+menuItem.Handler+"\"));\n");
}
script.Append("" + this.UniqueID + ".initialize();\n");
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(),this.UniqueID,script.ToString(),true);
string script2 = "$(document).ready(function() {" + this.UniqueID + ".set_ContextMenu('" + this.AttachedClientControlId + "');});\n";
this.Page.ClientScript.RegisterStartupScript(this.GetType(), this.UniqueID + "_onLoad", script2,true);
}
}
/// <summary>
/// 右键菜单设计器
/// </summary>
internal class WebContextMenuBuilder : ControlBuilder
{
public override bool AllowWhitespaceLiterals()
{
return false;
}
public override Type GetChildControlType(string tagName, System.Collections.IDictionary attribs)
{
if (string.Compare(tagName, "WebContextMenuItem", true) == 0)
{
return typeof(WebContextMenuItem);
}
return null;
}
}
}
这样一个右键菜单的服务器控件就实现了,那么我们在前台页面如何去用呢。
首先我们在前台aspx拖两个WebContextMenu服务器控件到页面上,别忘记先要拖个ScriptManager控件
</cc1:WebContextMenu>
<cc1:WebContextMenu ID="WebContextMenu2" runat="server" AttachedClientControlId="div1">
<cc1:WebContextMenuItem Text="添加" Image="images/db.ico" Handler="add" />
<cc1:WebContextMenuItem Text="编辑" Image="images/db.ico" Handler="edit" />
<cc1:WebContextMenuItem Text="导入Excel" Image="images/db.ico" Handler="inputExcel" />
<cc1:WebContextMenuItem Text="导出Excel" Image="images/db.ico" Handler="outputExcel" />
<cc1:WebContextMenuItem Text="" Image="" Handler="" />
<cc1:WebContextMenuItem Text="添加" Image="images/db.ico" Handler="add" />
<cc1:WebContextMenuItem Text="编辑" Image="images/db.ico" Handler="edit" />
<cc1:WebContextMenuItem Text="导入Excel" Image="images/db.ico" Handler="inputExcel" />
<cc1:WebContextMenuItem Text="导出Excel" Image="images/db.ico" Handler="outputExcel" />
<cc1:WebContextMenuItem Text="" Image="" Handler="" />
<cc1:WebContextMenuItem Text="添加" Image="images/db.ico" Handler="add" />
<cc1:WebContextMenuItem Text="编辑" Image="images/db.ico" Handler="edit" />
<cc1:WebContextMenuItem Text="导入Excel" Image="images/db.ico" Handler="inputExcel" />
<cc1:WebContextMenuItem Text="导出Excel" Image="images/db.ico" Handler="outputExcel" />
</cc1:WebContextMenu>
要设定右键菜单的区域:
第一种方式在.cs代码种添加菜单项目,我们给WebContextMenu1添加几个菜单项试试:
WebContextMenu1.MenuItems.Add(new WebContextMenuItem("编辑", "images/db.ico", "edit"));
WebContextMenu1.MenuItems.Add(new WebContextMenuItem("删除", "images/db.ico", "del"));
WebContextMenu1.MenuItems.Add(new WebContextMenuItem("导出Excel", "images/db.ico", "outputExcel"));
WebContextMenu1.MenuItems.Add(new WebContextMenuItem("导入Excel", "images/db.ico", "inputExcel"));
WebContextMenu1.AttachedClientControlId = "divSpan";
第二种方式直接在aspx页面中像给dropdownlist添加下拉项一样添加菜单项
其中为Text,Image,Handler均为空的菜单项为分割栏,大家不要感到奇怪
这样一个Web页面的右键服务器控件就开发完成了,截个图完成本文的编写。