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

Web 选项卡控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (12投票s)

2011年5月7日

CPOL

6分钟阅读

viewsIcon

68152

downloadIcon

2559

一个可在 C# 中动态创建的 Web 选项卡控件。使用 JavaScript,可以无需刷新页面即可更改选项卡,从而提高“账户信息”等页面的易用性。

更新:已添加记住上次选择的选项卡的功能!请参见下面的 C# 代码!

更新:使用 jQuery - 现在允许设置(也可从 C# 设置)选项卡过渡的 jQuery 动画。

更新:使用 HTML5 和 CSS3 实现漂亮的边框和圆角 - 基本来说,现在看起来更好了 :)

引言

我最近正在开发一个网站,该网站从多个来源提取大量信息并将其汇总到站点的单个账户中。但是,所有这些信息都必须由用户随时在站点上进行编辑。此外,该站点的关键目标是易用性和信息清晰度。因此,我面临着如何在不使用一个带有大量可编辑字段的长页面即可让用户轻松清晰地编辑所有信息这一难题。显而易见的解决方案是使用选项卡控件,但可以预见的是,网上已不存在可用的。因此,我创建了自己的自定义 Web 控件,并在本文中介绍,希望其他人也能轻松设置和使用它,并发现它和我一样有用。

背景

如果您具备基本的 CSS、HTML、JavaScript 知识,并且至少了解如何在 C# 中创建动态内容,那么这将非常有用。我建议以下链接作为良好的起点:

Using the Code

屏幕截图

选项卡控件的初始视图 - 基本选项卡

选项卡的个人选项卡

单击测试按钮后,“基本”选项卡上的文本框将设置为“Test OK. :)”

为了展示代码的工作原理,我们将逐步介绍构建 Default.aspx 页面的服务器端代码。代码如下:

//Create a tab control
TabControl TheTabCtrl = new TabControl("InfoTabCtrl");

//Block: Create and add a new tab page - BasicPage
TabPage BasicPage = new TabPage("BasicInfoTabPage", "Basic");

BasicPage.Controls.Add(ABox);

TheTabCtrl.Tabs.Add(BasicPage);
//End Block

//Block: Create and add a new tab page - PersonalPage
TabPage PersonalPage = new TabPage("PersonalInfoTabPage", "Personal");

Button AButton = new Button();
AButton.Text = "Test";
AButton.Click += new EventHandler(AButton_Click);
PersonalPage.Controls.Add(AButton);

TheTabCtrl.Tabs.Add(PersonalPage);
//End Block

//Add the tab control to the page output.
form1.Controls.Add(TheTabCtrl.GetControl);

第一行代码创建一个名为 TheTabCtrl 的新选项卡控件。构造函数接受一个参数 Id。这应该是选项卡控件的唯一 ID,因为它将在 JavaScript(本文后面)中用于跟踪选定的选项卡。然后可以使用 TheTabCtrl 添加选项卡页面并生成选项卡控件的输出。

接下来,代码创建一个新的 TabPage。选项卡页面的构造函数接受两个参数,第一个是选项卡页面的唯一 ID,它将在 JavaScript(本文后面)中用于更改当前显示的选项卡。第二个参数是选项卡的名称。这将是显示给用户的选项卡标题。在这种情况下,我选择了“Basic”作为标题,因为这是我的网站所需的信息类别之一。

向选项卡添加控件非常简单,如下一行所示。只需调用 ATabPage.Controls.Add。您可以添加任何派生自 System.Web.UI.Control 类的对象;这包括所有 WebControlsHtmlControlsControls 集合只是一个 Control 对象的列表,稍后将添加到选项卡中。
下一段代码只是添加了另一个名为“Personal”的选项卡页面,其中包含一个按钮,让我能够演示选项卡控件在多个选项卡中的工作方式。

最后一行代码将选项卡控件添加到页面。我决定不让 TabControl 类派生自 System.Web.UI.Control 类,因为它将意味着需要重写比我需要的更多方法。相反,我创建了一个名为 GetControl 的属性,该属性返回一个可以添加到页面任何部分的 WebControl。(注意:如果您的任何选项卡页面中使用带有事件的控件,则必须在 Page_Load 方法中添加 TabControl,以便控件的事件能够正确链接。)GetCotnrol 属性代码如下:

public WebControl GetControl
{
    get
    {
        WebControl TabCtrlWrapper = new WebControl(HtmlTextWriterTag.Div);
        TabCtrlWrapper.CssClass = ClassName;
        TabCtrlWrapper.ID = Id;

        TabCtrlWrapper.Controls.Add(TabSelectionControl);

        foreach (TabPage APage in Tabs)
        {
            TabCtrlWrapper.Controls.Add(APage.GetControl);
        }

        Literal BreakLit = new Literal();
        BreakLit.Text = "<div style=\"width:100%; float:none; 
        line-height:0px;\"> <script type=\"text/javascript\">" + 
        CreateChangeTabCall(Tabs[SelectedTab].Id) + "</script></div>";
        TabCtrlWrapper.Controls.Add(BreakLit);

        return TabCtrlWrapper;
    }
}

代码首先创建一个 WebControl,也就是最终将返回的控件,并设置其 IdCssClassId 是在构造函数中提供的,CssClass 默认设置为 ClassName,而 ClassName 默认设置为 'TabControl'。这会链接到提供的 CSS 文件,从而轻松设置选项卡控件的样式。然后,代码添加 TabSelectionControl(稍后将详细介绍)。此控件允许用户选择不同的选项卡。然后,枚举所有选项卡页面,并将其控件(稍后介绍)添加到最终控件中。最初,这些页面具有 display:none; 属性,以将它们全部隐藏起来。循环之后的代码块添加了一个 div,其中包含一个空格,用于强制 TabControl 的高度与包括选项卡页面和 TabSelectionControl 在内的整体高度一致。CSS 和浮动的怪癖是,一个没有文本但有浮动子元素的父元素,只有在非浮动子元素中有文本时,其高度才会等于这些元素的高度——我知道这很复杂且奇怪,但上面的解决方案非常简单。将 line-height 设置为 0 可以隐藏 div 的内容,使其看起来好像不存在一样。JavaScript 代码在选项卡控件加载后运行,因此会设置初始选定的选项卡。这可以通过服务器端设置 SelectedTab 属性来更改,该属性只是控件选项卡列表中选项卡的索引。

选项卡选择控件

创建构成选项卡选择部分的 Web 控件。此代码枚举所有选项卡,为每个选项卡添加一个单独的“按钮区域”,该区域显示选项卡的名称。每个“按钮区域”都有一个 onclick 事件,用于运行更改选项卡的 JavaScript 代码。

WebControl TheCtrl = new WebControl(HtmlTextWriterTag.Div);
TheCtrl.CssClass = "TabPageSelectionControl";

//Enumerate all tabs, adding a 'button area' for each one.
foreach (TabPage ATab in Tabs)
{
    //Create the web control that will be the 'button area'
    WebControl TabCtrl = new WebControl(HtmlTextWriterTag.Div);
    TabCtrl.CssClass = "TabPageSelectionTitle";
    //Add the onclick attribute using the (custom) 
    //CreateChangeTabCall method with the relevant TabId.
    TabCtrl.Attributes.Add("onclick", CreateChangeTabCall(ATab.Id));
    TabCtrl.Attributes.Add("style", "background-color:;");
    TabCtrl.ID = ATab.Id + "TitleCtrl";

    //Add a literal to display the name of the tab.
    Literal NameLit = new Literal();
    NameLit.Text = ATab.Name;
    TabCtrl.Controls.Add(NameLit);

    //Add the button area to the selection control.
    TheCtrl.Controls.Add(TabCtrl);
}

return TheCtrl;

TabPage 控件

将选项卡的标题添加到选项卡页面控件,然后添加用户在 Controls 集合中指定的所有控件。

WebControl TabPageWrapper = new WebControl(HtmlTextWriterTag.Div);
TabPageWrapper.CssClass = ClassName;
TabPageWrapper.ID = Id;
TabPageWrapper.Attributes.Add("style", "display:none;");

TabPageWrapper.Controls.Add(TitleCtrl);
foreach (Control ACtrl in Controls)
{
    TabPageWrapper.Controls.Add(ACtrl);
}

return TabPageWrapper;

重新选择用户上次选定选项卡的代码

if (IsPostBack)
{
    //Gets the selected tab's Id from the posted form
    string value = Request.Form[TheTabCtrl.Id + "_SelectedTab"];
    //Checks to make sure it's not an empty/null Id i.e. there actually wasn't one selected.
    if(!string.IsNullOrEmpty(value))
    {
        try
        {
            //Tries to selected the tab with that Id.
            //Try-catch used in case that tab no longer exists.
            TheTabCtrl.SelectedTab = TheTabCtrl.Tabs.IndexOf(TheTabCtrl.Tabs.Where(x => x.Id == value).First()); 
        }
        catch
        {
        }
    }
}  

使用 JavaScript 的新功能,您现在可以从表单回发中获取选项卡控件的上次选定选项卡。请参阅上面的代码了解如何操作 :)

客户端脚本

我已经展示了所有服务器端内容是如何工作的,那么客户端是如何工作的呢?嗯,我将从 JavaScript 开始,然后解释如何更改样式。JavaScript 代码非常简单,如下所示:

var CurrentTabs = [];

//The colour of the tab selector when selected
var SelectedBgColour = "#C7E9FF";
//The colour of the tab selector when not selected
var NotSelectedBgColour = "#99C8E8";

//Changes a tab control to a different tab using wanted jQuery effects
//TabControlName - The name of the tab control you are changing
//Id - The (full) Id of the tab to change to
//EffectIn (Opt) - The effect to use for bringing in the new tab. Default : fade
//EffectOut (Opt) - The effect to use for taking out the current tab. Default : fade
//Speed (Opt) - How long the transition should take (in milliseconds) : Default : 300
function ChangeTab(TabControlName, Id, EffectIn, EffectOut, Speed)
{
    //If not already showing the current tab
    if (CurrentTabs[TabControlName] != Id)
    {
        //Set-up the default values if necessary
        //JS allows testing for null/undefined by just evaluating the object as a boolean
        if (!EffectIn)
            EffectIn = "fade";
        if (!EffectOut)
            EffectOut = "fade";
        if (!Speed)
            Speed = 300;
        
        if (CurrentTabs[TabControlName] != null)
        {
            $("#" + CurrentTabs[TabControlName])
                    .hide(EffectOut, { direction: "vertical" }, Speed, null);
            $("#" + CurrentTabs[TabControlName] + "TitleCtrl")
                    .animate({ backgroundColor: NotSelectedBgColour }, Speed);
        } 
        
        //Resizes the tabs wrapper to fit the new tab
        $("#" + Id)
            .parent()
            .css("height", $("#" + Id)
            //Shows the current tab then gets its outer height including margins
            .show(EffectIn, {}, Speed, null)
            .outerHeight(true));
        //Changes the new tab's title control bgColour to selected
        $("#" + Id + "TitleCtrl").animate({ backgroundColor: SelectedBgColour }, Speed);

        //Stores the new tab as being the current tab (for page submission)
        CurrentTabs[TabControlName] = Id;

        //Stores the new tab in the form data for postback
        $("#" + TabControlName + "_SelectedTab").val(Id);
    }
}
$(document).ready(function ()
{
    //Set all the title control backgrounds to the not selected colour
    //Saves having to write it in two places i.e. the CSS and the JavaScript
    $(".TabPageSelectionTitle").css("background-color", NotSelectedBgColour);
}); 

CurrentTabs 用于跟踪哪个选项卡控件上的哪个选项卡已被选中。使用数组是为了使页面上可以有多个选项卡控件而不会发生冲突。

SelectedBgColour 是选定选项卡(在选项卡选择控件中)的选项卡标题的背景颜色代码或名称。

ChangeTab 方法会隐藏当前选中的选项卡(如果存在),然后显示所需的选定选项卡。它还会更改相关的样式(如上所示),然后存储新的选定选项卡。代码不言自明。

样式

除选定选项卡的标题背景颜色外,所有样式均在一个简短的 CSS 文件中完成。如下所示(并在 CSS 的注释中解释),更改 TabControl 的外观非常容易。我选择了鲜明、俗气的颜色,它们形成强烈的对比,只是为了清晰地显示选项卡控件的各个部分,您肯定想更改这些颜色。因此,CSS:

.TabControlTabsWrapper
{
    position:relative;
    width:100%;
    height:100%;
    overflow:hidden;
    /*Set this to change the tab background colour - this is a very light blue - off-white
          almost*/
    background-color:#FAFDFF;
    
    border:solid #000000;
    border-width:medium;
    border-bottom-left-radius:10px;
    border-bottom-right-radius:10px;
    -moz-border-bottom-left-radius:10px; /* Firefox 3.6 and earlier */
    -moz-border-bottom-right-radius:10px; /* Firefox 3.6 and earlier */
} 
.TabPageSelectionTitle
{
    float:left;
    padding:2px;
    padding-left:4px;
    padding-right:4px;
    border-right:2px solid #000000;
            
    border:solid #000000;
    border-width:medium;
    border-bottom:0px;
    border-top-left-radius:10px;
    border-top-right-radius:10px;
    -moz-border-top-left-radius:10px; /* Firefox 3.6 and earlier */
    -moz-border-top-right-radius:10px; /* Firefox 3.6 and earlier */
} 

并非全部 CSS,但有用的部分 - 这些设置了边框和边框的圆角。我故意在选项卡的右上角留了一个直角,我认为它在对比方面看起来不错,而且也呼应了另一侧。

历史

  • 2011/7/5 - 首次发布
  • 2012/5/22 - jQuery 和 HTML5/CSS3 更新
© . All rights reserved.