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

使用 AJAX 和 XML 创建级联下拉列表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.44/5 (15投票s)

2010年3月21日

CPOL

5分钟阅读

viewsIcon

41601

downloadIcon

697

本文将介绍如何创建级联下拉列表,以表示来自分层数据集的数据。我将讨论使用 AJAX 进行部分页面渲染来填充 ASPX 下拉列表的方法。我的数据库是一个简单的 XML 数据文件。

prog-snapshot.jpg

exec-snapshot.jpg

引言

本文将介绍如何创建级联下拉列表,以表示来自分层数据集的数据。我将讨论使用 AJAX 进行部分页面渲染来填充 ASPX 下拉列表的方法。我的数据库是一个简单的 XML 数据文件。

背景

本文是响应我另一篇文章《使用 jQuery 和 XML 创建级联下拉列表》中提出的一个询问而写成的 [1]。询问者想知道在为级联下拉列表编程时使用 jQuery 的安全问题。

我得说,“是的,存在安全问题,这是我们在客户端工作时总是会遇到的,并且我们无法同时消除它们”。在使用 jQuery 方法时,我发现无法通过使用 Web.config 文件来保护我的 XML 数据文件(它位于一个单独的文件夹中),而该文件可以阻止所有用户进入该文件夹。

所以,如果您的数据不重要,为了性能而牺牲安全性并不是一个坏主意,但当数据非常重要时,最好还是使用服务器端编程。在本文中,我将使用 ASPX 下拉列表,并且我的 XML 数据文件存放在一个受保护的文件夹中。我将使用 AJAX 来实现部分页面渲染,从而提高性能。此外,我还将显示一个部分更新进度条,以便让用户知道正在进行操作。

现在的问题是,应该选择 XML 数据文件还是 SQL Server 数据库。在我看来,答案是:当数据量小且静态时,最好使用 XML 数据文件,因为它避免了不必要的网站数据库服务器往返。但对于大型且动态变化的数据集,我们需要通过索引来增强数据检索能力,而任何核心数据库语言(如 SQL Server)都提供这种能力。因此,在后一种情况下,最好使用 SQL Server 而不是 XML。

Using the Code

在这里的演示程序中,我使用了一个 .dll 文件 Microsoft.Web.Preview.dll。这必须添加到程序的 Bin 文件夹中,才能实现部分页面更新进度面板的功能。接下来是 XML 文件(Motors.xml),它存放在一个名为“XMLFiles”的文件夹中,并有一个 Web.config 文件来保护对 Motors.xml 的访问。

Default.aspx 页面上,有三个下拉列表、一个 button、一个 UpdateProgress 控件(为此我们添加了 .dll 文件)和一个 Label 用于显示结果。所有这些都包含在 UpdatePanel 控件中,并将属性 ChildrenAsTriggers=”true” 设置为 true。这意味着从任何包含的控件触发的任何事件都会触发到服务器的异步回发。UpdateProgress 控件的显示/隐藏由下面的 jQuery 代码管理。

var prm = Sys.WebForms.PageRequestManager.getInstance(); 
prm.add_initializeRequest(InitializeRequest); 
prm.add_endRequest(EndRequest);
 
function InitializeRequest(sender,args) 
{ 
    $get('chainUpdate').style.display = 'block'; 
} 

function EndRequest(sender,args) 
{ 
    $get('chainUpdate').style.display = 'none'; 
}

在上面的代码中,chainUpdateUpdateProgress 控件的 ID,有两个函数,第一个函数在异步回发初始化时被调用,第二个函数在调用结束后被调用。

现在,我将讨论代码后置页面的代码。在页面加载事件中,我将我的 XML 文件加载到数据集中,并将其添加到缓存以提高性能。下一个事件调用是 Level-Zero 下拉列表(drpMain)的 selected index 更改时。处理函数如下所示。

protected void drpMain_SelectedIndexChanged(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(1200);
    
    if (drpMain.SelectedValue == "0")
    {
        drpMoto.Items.Clear();
        drpBrand.Items.Clear();
        drpMoto.Enabled = false;
        drpBrand.Enabled = false;
        btnGo.Enabled = false;
    }
    else if (drpMain.SelectedValue == "1")
    {
        drpMoto.DataTextField = "mcname";
        drpMoto.DataValueField = "mcid";
        drpMoto.DataSource = ds.Tables["motoc"];
        drpMoto.DataBind();
        drpMoto.Enabled = true;
        drpBrand.Items.Clear();
        drpBrand.Enabled = false;
        btnGo.Enabled = false;
    }
    else if (drpMain.SelectedValue == "2")
    {
        drpMoto.DataTextField = "mbname";
        drpMoto.DataValueField = "mbid";
        drpMoto.DataSource = ds.Tables["motob"];
        drpMoto.DataBind();
        drpMoto.Enabled = true;
        drpBrand.Items.Clear();
        drpBrand.Enabled = false;
        btnGo.Enabled = false;
    }
}

上面的处理函数中的第一行用于暂停线程 1200 毫秒,这是 UpdateProgress 控件显示的最短时间。您可以根据需要进行更改。

现在会检查 selectedvalue 是否为默认项(零)。如果选择了默认项,则会清除 Level1drpMoto)和 Level2drpBrand)下拉列表中的项目,并禁用这两个下拉列表以及“Go”按钮。

在第二种情况下,当 selectedvalue1 时(即选择了 drpMain 下拉列表中的第二项,在本例中为“cars”),相关于汽车的数据将从数据集中提取,并绑定到 Level1drpMoto)的下拉列表中,同时更改 DataTextFieldDataValueField 的属性值。现在 drpMoto 列表将被启用。

在第三种情况下,当选定的值为 2 时(在本例中为“bikes”),将提取相关于自行车的数据,并绑定到 Level1drpMoto)的下拉列表中,同时启用该列表。

您会注意到,在所有选定项的更改中,整个页面都不会回发到服务器,而是进行部分回发,并通过 UpdateProgress 控件提供缓解。

现在是时候讨论为 Level1 下拉列表(drpMoto)中的选定项更改时编写的事件处理程序了,如下所示。

protected void drpMoto_SelectedIndexChanged(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(1200);
    
    if (drpMoto.SelectedItem.Value == "0")
    {
        drpBrand.Items.Clear();
        drpBrand.Enabled = false;
        btnGo.Enabled = false;
    }
    else if (drpMain.SelectedValue == "1" && drpMoto.SelectedItem.Value != "0")
    {
        DataView dView = new DataView(ds.Tables["motocb"]);
        dView.RowFilter = "mcid='" + drpMoto.SelectedValue.Trim() + "'";
        dView.Sort = "mcbname asc";
        drpBrand.DataTextField = "mcbname";
        drpBrand.DataValueField = "mcbid";
        drpBrand.DataSource = dView;
        drpBrand.DataBind();
        drpBrand.Enabled = true;
        btnGo.Enabled = true;
    }
    else if (drpMain.SelectedValue == "2" && drpMoto.SelectedItem.Value != "0")
    {
        DataView dView = new DataView(ds.Tables["motobb"]);
        dView.RowFilter = "mbid='" + drpMoto.SelectedValue.Trim() + "'";
        dView.Sort = "mbbname asc";
        drpBrand.DataTextField = "mbbname";
        drpBrand.DataValueField = "mbbid";
        drpBrand.DataSource = dView;
        drpBrand.DataBind();
        drpBrand.Enabled = true;
        btnGo.Enabled = true;
    }
}

在上面的处理程序中,首先有两个条件检查。第一个是 drpMoto 下拉列表中的 selectedvalue 为零时,第二个是 drpMoto 下拉列表中的 selectedvalue 不为零时。此外,当 drpMoto 下拉列表中的 selectedvalue 不为零时,还有两种情况:如果 drpMain 下拉列表中的 selectedvalue1(代表“Cars”),或者为 2(代表“Bikes”)。

在第一个条件中,当 drpMoto 中的 selectedvalue0 时,drpBrand 中的项目将被清除,并且 drpBrandbtnGo 都将被禁用。

在第二种情况下,我们需要提取所有汽车的 brand 节点,并过滤以匹配 drpMoto 中的选定项。然后 Level2drpBrand)的下拉列表将进行绑定,并且 drpBrandbtnGo 将被启用。

在第三种情况下,我们需要提取所有自行车(bikes)的 brand 节点,并过滤以匹配 drpMoto 中的选定项。然后 Level2drpBrand)的下拉列表将进行绑定,并且 drpBrandbtnGo 将被启用。

现在所有下拉列表都已填充并启用了按钮。代码后置页面上的最后一个处理函数在单击按钮时被触发,如下所示。

protected void btnGo_OnClick(object sender, EventArgs e)
{
    lblResult.Text = "Searched for: " + 
	drpBrand.SelectedItem.Text.Replace("(","").Replace(")","") + " " + 
	drpMoto.SelectedItem.Text + " " + 
	drpMain.SelectedItem.Text.Replace("s","") + "(s)";
}

上面的处理程序用于简单地在标签字段中显示结果。

关注点

实际的示例代码已附在附件中。您在查看下载的附件时将很容易理解。在这里,您可能对在客户端使用 jQuery 填充下拉列表感兴趣,请参阅我的文章 使用 jQuery 和 XML 创建级联下拉列表

结束语

希望这些内容对您有所帮助。感谢您的阅读。祝您好运!

© . All rights reserved.