前一段時間寫了幾篇關於控件開發的文章,一直沒有一個實戰的控件出來。年前的一個項目中,發現一個比較好的效果,後來爲了方面開發,就開發成了一個容器控件。來看控件的幾個效果圖:
運行效果圖:
設計時的效果圖:
控件的原理
很顯然控件的最外層是標籤
,內容部分是包在內部的一個裏面的,通過控制div的display來實現效果的。大體的前臺html結構:
UpdownPanel的實現
首先,確認UpdownPanel控件不需要繼承某一個控件,但需要一些設計時的支持,如:邊框的顏色、高、寬,所以可以確定控件繼承於WebControl。控件標籤的內容要解釋成子控件,同時需要支持事件回傳來通知是否已經打開,所以控件還需要繼承IPostBackEventHandler。
我們先來看控件的屬性:
///
/// 標題
///
public string Title
{
get
{
if (ViewState["Title"] == null)
return String.Empty;
return ViewState["Title"].ToString().Trim();
}
set
{
ViewState["Title"] = value;
}
}
///
/// 距離左邊距離
///
public Unit PandingLeft
{
get
{
if (ViewState["PandingLeft"] == null)
return new Unit("20px");
return new Unit(ViewState["PandingLeft"].ToString());
}
set
{
ViewState["PandingLeft"] = value;
}
}
///
/// 距離上邊距離
///
public Unit PandingTop
{
get
{
if (ViewState["PandingTop"] == null)
return new Unit("20px");
return new Unit(ViewState["PandingTop"].ToString());
}
set
{
ViewState["PandingTop"] = value;
}
}
///
/// 是否打開
///
[DefaultValue(false)]
public bool IsOpen
{
get
{
if (ViewState["IsOpen"] == null)
return false;
return Convert.ToBoolean(ViewState["IsOpen"]);
}
set
{
ViewState["IsOpen"] = value;
}
}
Title屬性是表示標題,IsOpen屬性表示是否已經展開,屬性都很簡單。
控件的事件參數類:
///
/// IsOpenChanged事件的參數
///
public class ChangedArgs : EventArgs
{
private bool _isOpened;
public bool IsOpened
{
get
{
return _isOpened;
}
set
{
_isOpened = value;
}
}
public ChangedArgs(bool bOpened)
{
IsOpened = bOpened;
}
}
事件回傳:
static object _isOpenChanged = new object();
public event EventHandler<ChangedArgs> IsOpenChanged
{
add
{
Events.AddHandler(_isOpenChanged, value);
}
remove
{
Events.RemoveHandler(_isOpenChanged, value);
}
}
public void RaisePostBackEvent(string eventArgument)
{
ChangedArgs args = new ChangedArgs(Convert.ToBoolean(eventArgument.ToString()));
if (args.IsOpened)
IsOpen = false;
else
IsOpen = true;
if (Events[_isOpenChanged] != null)
{
(Events[_isOpenChanged] as EventHandler<ChangedArgs>)(null, args);
}
}
控件的呈現時候,首先需要重寫TagKey爲"",同時要注意註冊事件回傳的腳本,跟輸出自己的控制腳本。這裏就不列出所有的呈現的代碼了,就看下關鍵的幾行代碼:
protected override void RenderContents(HtmlTextWriter writer)
{
//呈現Legend
writer.AddStyleAttribute(HtmlTextWriterStyle.FontStyle, this.Font.ToString());
writer.AddStyleAttribute(HtmlTextWriterStyle.FontSize, this.Font.Size.ToString());
writer.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "pointer");
//-------------加載事件回傳------------------
string strRef = Page.ClientScript.GetPostBackClientHyperlink(this,IsOpen.ToString());
writer.AddAttribute(HtmlTextWriterAttribute.Href, strRef);
writer.AddStyleAttribute(HtmlTextWriterStyle.TextDecoration, "none");
writer.RenderBeginTag(HtmlTextWriterTag.A);
//標題
writer.Write("   "+this.Title);
writer.RenderEndTag();
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Id, "upChild" + this.ClientID);
writer.AddStyleAttribute(HtmlTextWriterStyle.Height, this.Height.ToString());
//判斷是否打開
if (!this.IsOpen)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
}
writer.AddStyleAttribute(HtmlTextWriterStyle.PaddingTop, this.PandingTop.ToString());
writer.RenderBeginTag(HtmlTextWriterTag.Div);
//呈現子控件
for (int i = 0; i < this.Controls.Count; i++)
{
this.Controls[i].RenderControl(writer);
}
writer.RenderEndTag();
}
最後要注意的一點就是我們要讓控件能夠在設計時支持,還需要自定義一個ControlDesigner:
public class UpDownPanelDesigner : System.Web.UI.Design.ContainerControlDesigner
{
public override string FrameCaption
{
get
{
return "UpDownPanel的內容";
}
}
}
因爲UpDownPanel控件是容器控件,所以我們繼承於ContainerControlDesigner,同時需要在控件上標識:
[Designer(typeof(UpDownPanelDesigner))]
public class UpDownPanle:WebControl,IPostBackEventHandler
{}
這下就可以使用了,只不過控件還比較粗糙,在以後會逐步完善,還請大家批評,呵呵。
自定義asp.net控件開發系列鏈接: