基于样式和区域的面板容器

分享于 

19分钟阅读

Web开发

  繁體

Sample Image - Image1.gif

介绍

我将试着解释如何使用 ASP.NET 2.0使用现有的控件编辑具有样式和区域的简单面板。 我们叫它 shSimplePanel。

Framework.NET 2.0为我们提供了新的控件和用于生成自定义控件的基类。 System.Web.UI.WebControls.CompositeControl 为实现 INamingContainerWebControl的生成自定义控件提供基类。 System.Web.UI.WebControls.CompositeControlDesigner 提供用于生成自定义设计时间编辑器的基类,该编辑器基于区域编辑。 当我想像面板控件一样构建自定义控件时,我没有从面板中进行 inherit,因为在设计时 只需要一个方形控件。我希望自定义控件能够从工具箱拖放并添加标题文本,标题图像和内容图像。

shSimplePanel在设计时执行这些任务。 另外,我实现了一类"飞行时的图像",允许在运行时对图像进行shSimplePanel拉伸控制。 虽然这个类不完整,但它是一个很好的工具。 在本文的结尾部分,我提供了一些参考。

背景

当我决定做这个控制时,我在网上搜索可能帮助我的文档和代码。 Mohammed编写了一个基于编辑区域的 WebTabControl插件。 它是这个简单控件的基础,通过基于MSDN区域的少量帮助,它对如何在设计时使用区域是一个出色的参考。 这里控件基于样式类型的技术,在书"开发 Microsoft ASP.NET 服务器控件和组件。"中编写,这是一个控件,用于实现标题文本,标题图像,内容背景图像,标题和内容以及设计时的区域编辑。 shSimplePanel的复合是由三个面板组成的。

Screenshot - Image2.gif

使用代码

这里自定义控件实现 VS.NET 2005在设计时使用的属性。 使用这里控件很容易,只需将它的拖放到ASPX页上即可。

<cc1:shSimplePanel ID="ShSimplePanel1" runat="server" Height="269px" 
 TitleText="Title shSimplePanel"> <ContentTemplate>
 This is a Content of shSimplePanel. You can to add controls too.<br/>
 <asp:HyperLink ID="HyperLink1" runat="server" 
 NavigateUrl="HypExample1.aspx" Width="225px"> HyperLink Example 1</asp:HyperLink><br/> 
 <asp:HyperLink ID="HyperLink2" runat="server" 
 NavigateUrl="HypeExample2.aspx" Width="223px"> HyperLink Example 2</asp:HyperLink><br/>
 <asp:Button ID="Button1" runat="server" Text="Button" 
 Width="93px" OnClick="Button1_Click"/>
 </ContentTemplate></cc1:shSimplePanel>

生成代码

首先,你需要从 VS.NET 2005向导创建一个WebControlLibrary项目。 然后,实现这些引用:

添加引用

接下来,为shSimplePanel实现这个框架:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Text;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;using System.Drawing;using System.Collections;using System.Web.UI.Design;using System.Web.UI.Design.WebControls;using System.Drawing.Design;using System.ComponentModel.Design;namespace shSimplePanel
{
 [ParseChildren(true)]
 [Designer(typeof(shSimplePanelControlDesigner))]
 [ToolboxData("<{0}:shSimplePanel runat="server" 
 width=300px height=100px>")]
 [ToolboxBitmap(@"Please Put here some path of your 
 ToolboxBitmap 16x16 pixeles")]
 publicclass shSimplePanel : CompositeControl
 {..the code..}

所有CompositeControl自定义控件都实现类似的。 我们稍后将定义 Designer metadataParseChildren(true) 表示子控件的所有控件都将作为属性进行解析。 ToolboxBitmap 允许在自定义控件中添加一些位图。 现在,我们将实现面板控件和控件中使用的变量:

internal List<IAttributeAccessor> regions;private csImageOnFly IOFTitle = new csImageOnFly();private csImageOnFly IOFContent = new csImageOnFly();private ITemplate _contentTemplate;private Style _StyleTitle;private Style _StyleContent;//Controlsprivate Panel cPanelMain;private Panel cPanelTitle;private Panel cPanelContent;private Label cLabelTitle;

我们将面板网页控件和标签定义为 LabelTitle。 iPhone 7 还没出来,我们已经在iPhone上获取细节 8,或者不管是想到下一步。 internal List<IAttributeAccessor> regions 变量定义了我们的区域组件。 因为我们将在shSimplePanelControlDesigner类中使用它,所以它被声明为 internal。 因为它将表示我们将在该列表中添加控件,所以这个变量有一个属性 IAttributeAccessor。 定义了csImageOnFly类,以便在标题和内容上启用图像拉伸。 声明 private ITemplate _contentTemplate 以使模板定义一个可以编辑区域。 最后是标题和内容面板的Style。 接下来,我们将定义这里自定义控件的属性:

#region Properties of shSimplePanel. . .. for see all properties see the code please
 #region public ITemplate ContentTemplate [Browsable(false)]
 [MergableProperty(false)]
 [DefaultValue(null)]
 [PersistenceMode(PersistenceMode.InnerProperty)]
 [TemplateContainer(typeof(shSimplePanel))]
 [TemplateInstance(TemplateInstance.Single)]
 public ITemplate ContentTemplate
 {
 get{return _contentTemplate;}
 set{_contentTemplate = value;}
 }
 #endregion. . .. for see all properties see the code please#endregion Properties of shSimplePanel

这些属性可能对你很熟悉;惟一特殊的属性是 ContentTemplate。 因为没有在 VS.NET.的属性资源管理器中显示,所以我声明了 Browsable(false)TemplateContainer(typeof(shSimplePanel)) 属性作为子控件的主体容器。 最后 TemplateInstance(TemplateInstance.Single) 允许访问子控件的控件,如下所示。 例如 Button web控件将作为它的NameID 访问。 现在我们重写 protected CreateChildControls 方法来创建控件,并设置区域可以编辑:

protectedoverridevoid CreateChildControls()
{
 cLabelTitle = new Label();
 cPanelTitle = new Panel();
 cLabelContent = new Label();
 cPanelContent = new Panel();
 cPanelMain = new Panel();
 if (_contentTemplate!= null)
 {
 _contentTemplate.InstantiateIn(cPanelContent);
 }
 cPanelMain.Controls.Add(cPanelTitle);
 cPanelMain.Controls.Add(cPanelContent);
 regions = new List<IAttributeAccessor>();
 regions.Add(cPanelContent);
 Controls.Add(cPanelMain);
}

这里我只构建了shSimplePanel的骨架,用面板编辑了,最后添加了 List<IAttributeAccessor>的区域。 protected Render 方法将允许在页面上写入控件。 下面是代码:

protectedoverridevoid Render(HtmlTextWriter writer)
{
 try {
 if (cPanelMain == null)
 CreateChildControls();
 //Label Titulo  cLabelTitle.Width = Width;
 cLabelTitle.Text = TitleText;
 //Panel Titulo cPanelTitle.Width = Width;
 cPanelTitle.Height = TitleHeight;
 cPanelTitle.Wrap = true;
 if ((ImageTitle!= null) && (ImageTitle.Length >0))
 {
 string resStretch;
 if (StretchImageTitle)
 {
 if (DesignMode)
 {
 cPanelTitle.BackImageUrl = ResolveClientUrl(ImageTitle);
 }
 else {
 IOFTitle.SourceFileName = 
 HttpContext.Current.Server.MapPath(ImageTitle);
 resStretch = 
 IOFTitle.StartConvertTo(
 Convert.ToInt32(cPanelTitle.Width.Value), 
 Convert.ToInt32(cPanelTitle.Height.Value), "_tempTitle");
 if (resStretch!= null)
 cPanelTitle.BackImageUrl = "~/" + 
 resStretch.Substring(Page.Server.MapPath(
 HttpContext.Request.ApplicationPath).Length+1);
 else {
 cPanelTitle.BackImageUrl = ResolveClientUrl(ImageTitle);
 writer.Write("IOFTitle Error:" + IOFTitle.ErrorDescription + 
 "<br>");
 }
 }
 }
 else cPanelTitle.BackImageUrl = ResolveClientUrl(ImageTitle);
 }
 else//set empty string at ImageUrl of Panel Title {
 cPanelTitle.BackImageUrl = String.Empty;
 }
 cPanelTitle.Controls.Add(cLabelTitle); 
 //Add the Label Title at cPanelTitleif (_StyleTitle!= null) 
 //Apply the Style at cPanelTitle  cPanelTitle.ApplyStyle(StyleTitle);
 cPanelTitle.HorizontalAlign = HorizontalAlignTitle; 
 //And the property HorizontalAlign for Title. . . The same technics is applied at Content Panel. See the code
 }
 catch (Exception e)
 {
 writer.Write("Render Error: <br>" + e.Message);
 }
}

这段代码简单易用。 首先,确保使用 CreateChildControls() 方法创建所有子控件。 稍后,在面板上建立相同的宽度。 我们确保设置了一个图像,如果需要,拉伸。 csImageOnFly是一个简单的类,它在同一路径上创建原始图像的副本但调整大小。 要创建调整大小的图像,它需要最终宽度和高度值,原始完整路径和作为创建图像的后缀的文本。

为了获得图像的完整路径,我使用了 HttpContext.Current.Server.MapPath 方法。 此类的问题是,它总是创建图像大小调整大小,不允许自动删除。 :- ( 最后,这里方法返回创建的新图像的路径,如果出现错误,则返回 null )。 之后,只在面板中应用一些属性和样式。 在内容面板中应用同样的技术。 对于此类,我使用内容和标题面板的样式。 以下是这些属性:

#region Custom Styles[
Category("Appearance"),
DefaultValue(null),
PersistenceMode(PersistenceMode.InnerProperty),
Description("PanelTitle Style"),
]publicvirtual Style StyleTitle
{
 get {
 if (_StyleTitle == null)
 {
 _StyleTitle = new Style();
 if (IsTrackingViewState)
 ((IStateManager)_StyleTitle).TrackViewState();
 }
 return _StyleTitle;
 }
}
... for the title style see the code#endregion

这些属性只是用户的声明。 样式的作业是针对 protected 方法 LoadViewStateSaveViewStateTrackViewState 进行管理的。 我将展示如何处理它:

#region Custom state managementprotectedoverridevoid LoadViewState(object savedState)
{
 if (savedState == null)
 {
 base.LoadViewState(null);
 return;
 }
 else {
 object[] myState = (object[])savedState;
 if (myState.Length!= 3)
 {
 thrownew ArgumentException("Invalid view state");
 }
 base.LoadViewState(myState[0]);
 ((IStateManager)StyleTitle).LoadViewState(myState[1]);
 ((IStateManager)StyleContent).LoadViewState(myState[2]);
 }
}protectedoverrideobject SaveViewState()
{
 // Customized state management to save the state of styles. object[] myState = new object[3];
 myState[0] = base.SaveViewState();
 if (_StyleTitle!= null)
 myState[1] = ((IStateManager)_StyleTitle).SaveViewState();
 if (_StyleContent!= null)
 myState[2] = ((IStateManager)_StyleContent).SaveViewState();
 return myState;
}protectedoverridevoid TrackViewState()
{
 // Customized state management to track the state// of styles.base.TrackViewState();
 if (_StyleTitle!= null)
 ((IStateManager)_StyleTitle).TrackViewState();
 if (_StyleContent!= null)
 ((IStateManager)_StyleContent).TrackViewState();
}#endregion

在"开发 Microsoft ASP.NET 服务器控件和组件。"中实现这些技术只保存和加载样式保存在状态管理器中。 检查它是否始终保存在pos零 base.SaveViewState() 中。

shSimplePanelControlDesigner类继承 CompositeControlDesigner 以启用区域可以编辑。 首先,我们重写 Initialize 方法:

publicclass shSimplePanelControlDesigner : CompositeControlDesigner
{
 private shSimplePanel _shSimplePanel;
 privateint _currentRegion = -1;
 privateint _nbRegions = 0;
 publicoverridevoid Initialize(IComponent component)
 {
 _shSimplePanel = (shSimplePanel)component;
 base.Initialize(component);
 SetViewFlags(ViewFlags.DesignTimeHtmlRequiresLoadComplete, true);
 SetViewFlags(ViewFlags.TemplateEditing, true);
 }
...
}

在这里,我们得到了组件 shSimplePanel,并启用了设计时模式 SetViewFlags(ViewFlags.TemplateEditing, true); 然后重写 CreateChildControls 方法以设置区域的NAME 属性:

protectedoverridevoid CreateChildControls()
{
 base.CreateChildControls();
 if (_shSimplePanel.regions!= null)
 {
 _nbRegions = _shSimplePanel.regions.Count;
 for (int i = 0; i < _nbRegions; i++)
 {
 _shSimplePanel.regions[i].SetAttribute(
 DesignerRegion.DesignerRegionAttributeName, i.ToString());
 }
 }
}

代码中,我们获取shSimplePanel类的internal List 区域并设置名称。 然后重写 OnClick 事件以获取选中的当前区域:

protectedoverridevoid OnClick(DesignerRegionMouseEventArgs e)
{
 base.OnClick(e);
 _currentRegion = -1;
 if (e.Region!= null)
 {
 for (int i = 0; i < _nbRegions; i++)
 {
 if (e.Region.Name == i.ToString())
 {
 _currentRegion = i;
 break;
 }
 }
 UpdateDesignTimeHtml();
 }
}

当用户单击内容面板时,onclick 被激发。 在这里我们将获取当前区域并更新设计时间 HTML。 为此,我们重写 GetDesignTimeHtml 方法:

publicoverridestring GetDesignTimeHtml(DesignerRegionCollection regions)
{
 this.CreateChildControls();
 for (int i = 0; i < _nbRegions; i++)
 {
 DesignerRegion r;
 if (_currentRegion == i)
 r = new EditableDesignerRegion(this, i.ToString());
 else r = new DesignerRegion(this, i.ToString());
 regions.Add(r);
 }
 if ((_currentRegion >= 0) && (_currentRegion < _nbRegions))
 regions[_currentRegion].Highlight = true;
 returnbase.GetDesignTimeHtml(regions);
}

本文中,我们为选中的当前区域设置设计器可编辑区域,稍后,我们只在该区域中做了一个高亮。 当你重写属性 TemplateGroups 时。

publicoverride TemplateGroupCollection TemplateGroups
{
 get {
 TemplateGroupCollection collection = new TemplateGroupCollection();
 TemplateGroup group = new TemplateGroup("ContentTemplate");
 TemplateDefinition definition = new TemplateDefinition(this, 
 "ContentTemplate", _shSimplePanel, "ContentTemplate", false);
 group.AddTemplateDefinition(definition);
 collection.Add(group);
 return collection;
 }
}

。你可以在设计时获取区域组的集合,如显示的图像:

在设计时编辑

最后,重写 GetEditableDesignerRegionContentSetEditableDesignerRegionContent:

publicoverridestring GetEditableDesignerRegionContent(
 EditableDesignerRegion region)
{
 IDesignerHost host = (IDesignerHost)Component.Site.GetService(
 typeof(IDesignerHost));
 if (host!= null)
 {
 ITemplate contentTemplate;
 if (_currentRegion == 0)
 {
 contentTemplate = _shSimplePanel.ContentTemplate;
 return ControlPersister.PersistTemplate(contentTemplate, host);
 }
 }
 returnString.Empty;
}publicoverridevoid SetEditableDesignerRegionContent(
 EditableDesignerRegion region, string content)
{
 if (content == null)
 return;
 IDesignerHost host = (IDesignerHost)Component.Site.GetService(
 typeof(IDesignerHost));
 if (host!= null)
 {
 ITemplate template = ControlParser.ParseTemplate(host, content);
 if (template!= null)
 {
 if (_currentRegion == 0)
 {
 _shSimplePanel.ContentTemplate = template;
 }
 }
 }
}

使用这里方法,我们可以在 ControlParserControlPersister 中的设计时编辑当前模板。

结束语

有那么多的文件可以帮助我们。 本书提及和其他文章对于开发定制控件非常适合初学者。

我希望这对你有用。 如果我的英文或者代码有错误,请接受我的道歉并通知我。 感谢你的这里空间和时间。

历史记录

  • 文章编辑并发布到主文章库。
  • 09/11/2006 property属性中的ViewState。
    • 运行时,由于未实现视图状态,属性丢失了值。 属性中使用的private 变量已经被删除。

BASE  style  Contain  PAN  PANE  面板  
相关文章