处理多个DropDown选择的更好方法

时间:2011-09-24 14:48:15

标签: c# .net-2.0 c#-2.0 asp.net-2.0 observer-pattern

enter image description here

我有一个包含多个DropDowns的菜单。我添加了代码,但目前,它完全驻留在代码隐藏文件中。我想使用任何设计模式以简单而整洁的方式处理各种选择。

报告生成标准如下:

报告类型DropDown选项包括:

  
      
  1. 方案类型
  2.   
  3. 方案逐
  4.   
  5. 区逐
  6.   
  7. 逐块
  8.   
  9. 所有
  10.   

默认情况下,仅启用第一个DropDown。从此DropDown中选择一个选项,可启用相应的DropDowns。

不仅如此,SchemeDistrictBlock DropDowns的值也会在使用从任何这些DropDowns或Scheme Type DropDown中选择项目时更改AJAX

它经常涉及各种SQL查询和启用/禁用DropDowns。我现在的代码变得混乱了许多IFEndIfs

我想知道是否使用Observer pattern或使用Classes的任何方法来简化此操作。有哪些方法可以使这些多项选择和DropDowns的填充变得易于管理和简单?

在下面编辑以明确要求

让我进一步澄清。

第一个DropDown是DropDown键,在页面打开时默认启用。默认情况下禁用所有其他DropDowns。但这并不意味着Cascading DropDown是正确的选择,因为从孩子DropDowns中选择是随机的。

整个计划是为每个DropDown以可理解的形式简化代码。根据选择,有许多Ifs和ElseIfs用于选择正确的查询。

例如:用户从报告类型主DropDown中选择District-wise report。在这种情况下,启用了三个子DropDowns,即

Scheme Type

Scheme

District

如果用户从Scheme Types List中选择“ALL”,则所有类别中的所有类型的方案都会在Scheme DropDown中填充。

如果用户从选项中选择特定的方案类型:Urban,Rural或Other,则Scheme DropDown会过滤方案的名称。

现在,Scheme DropDown还有一个选项ALL。用户可以选择ALL或选择任何特定方案。

与区相同。如果选择了ALL,则Scheme DropDown中的方案将采用所有区域中的所有方案,但如果选择了特定区域,则Scheme DropDown必须填写此区域的过滤方案。

请注意,在这种情况下,我们现在正在以相反的顺序移动,因为District DropDown再次过滤Scheme DropDown。

同样适用于Block DropDown。

要检查其他所选选项,有多种条件。假设用户没有选择任何选项或用户选择ALL。

我想用每个DropDown的名称创建单独的类。对于DropDown中的任何更改,这些类应该保持听力通知(Observer)。

我想我能澄清一下。

5 个答案:

答案 0 :(得分:5)

使用AJAX Control Toolkit是符合您要求的解决方案。

在AJAX Control Toolkit中,有CascadingDropDown Control

标记语法:

<ajaxToolkit:CascadingDropDown ID="ddlReportType" runat="server"
    TargetControlID="ddlSchemeType"
    Category="SchemeType"
    PromptText="Please select a ReportType"
    LoadingText="[Loading Report Types...]"
    ServicePath="ReportService.asmx"
    ServiceMethod="GetDropDownReportTypeContents"
    ParentControlID="DropDownList1"
    SelectedValue="SomeValue" />

然后你需要创建一个Web服务和几个Web方法,因为它具有以下方法签名,

[System.Web.Services.WebMethod]
[System.Web.Script.Services.ScriptMethod]
public CascadingDropDownNameValue[] GetDropDownReportTypeContents(
       string knownTypeValues, string typevalue) { ... }

更新

你使用if-Else-If做了类似的事情。如果答案是关于假设的,并且纯粹是实现的一个例子。

    string query = "SELECT * FROM Reports";
    List<string> filters = new List<string>();
    bool ReportType = true;
    bool SchemeType = true;
    bool Scheme = true;
    bool District = true;
    bool Block = true;

    if (ReportType)
        filters.Add("ReportType = true");
    if (SchemeType)
        filters.Add("SchemeType = true");
    if (Scheme)
        filters.Add("Scheme = true");
    if (District)
        filters.Add("District = true");
    if (Block)
        filters.Add("Block = true");

    if (filters.Count() > 0)
    {
        query = query + " WHERE " + string.Join(" AND ", filters.ToArray());
    }

我希望我的回答可以帮助你

谢谢和问候

Harsh Baid

答案 1 :(得分:2)

因为看起来你可以使用Javascript完成所有这个客户端,为什么你这么多查询你的数据库?您应该持久保存数据客户端和服务器端。您可以调用所有相关的下拉数据,对其进行缓存,并从客户端调用WebMethod,该WebMethod将返回包含所需数据的JSON。对于服务器端对象持久性,您应该查看Entity Framework 4.1,其中每个对象都是表的表示。

我会将jQuery与Knockout JS一起使用,或者只使用jQuery,使用JSON在客户端持久保存数据,无需返回并转发到SQL服务器。

这是Knockout JS的一个很好的例子 http://knockoutjs.com/examples/cartEditor.html

当然,除非数据频繁变化。

答案 2 :(得分:2)

不完全是您正在寻找的内容,但您可能想了解我是如何使用jQuery在mvc中解决类似问题的。使用web methods代替mvc操作可以在webforms中实现相同。

这是一个分为3个部分的故事,代码可以在bitbucket上找到。您可以从表单第2部分开始,首先是创建演示应用程序和设置数据库。

http://blog.goranobradovic.com/2011/06/asp-net-mvc3-app-part-2-ajax-cascading-dropdown/

有2个下拉列表的工作示例,但我使用相同的解决方案3和4没有问题。

<强>更新 由于您有可用的来源,我将仅在此处更改相关行。防止多个ajax调用的调整将把选项的值放在第一个选择id(或id到值无关紧要),或者你可以在依赖的下拉列表中使用某些属性,如果你不能改变id和值,但我会保留这很简单。然后,在主下拉列表的更改事件中,检查是否需要加载目标:

$('#' + target.attr('cascading-dependson')).change(function () {
        if($(this).find("option:selected").val() == $(target).attr("id")){ // this is added if
            $(target).removeAttr("disabled");  // added
            selectFromAjax($(target).attr('cascading-loadfrom'),
            { id: $(this).find("option:selected").val() },
            target);
        }
        else {  //added
            $(target).attr("disabled", "disabled");
        }
    });

如果您不想使用id,则可以轻松更改此选项以使用select的某些自定义属性。

更新2 我刚刚看到你更新了问题。在我看来,有一种情况需要刷新所有依赖的下拉列表。为此你需要有所有下拉列表的id-s,需要在最后一个主选择选项的值中刷新,separeted即“,”,这样你就可以检查它的任何val().split(",")是否等于依赖的id下拉列表,或者您可以在dependend中包含属性,该属性包含需要刷新的所有选项的值。您在我的代码中看到selectFromAjax的选项是下拉列表中的选定值和主字段的名称。由于您可能需要在此处使用服务器代码来处理您的某些值,我建议您使用第二种方法,即 - 将自定义属性添加到dependend下拉列表,其中您将从master中选择相关选项的值对于该字段,依赖项应在选中时加载。

你明白我的建议吗?

答案 3 :(得分:1)

如果我正确理解你的范例,那么,你有一个下拉列表(报告类型)决定是按方案类型,方案,区域或区块(或以上所有方式)进行选择。如果你有“全部”选项,我建议要么只有两个下拉菜单(一个用于报告类型,另一个用于其标签更改以匹配)或者取消报告类型下拉菜单在每个其他人旁边放一个单选按钮,以选择你想要的。包含“全部”选项时,您可能不会使事情复杂化;例如,您可以再添加一个单选按钮并启用所有四个下拉列表。

但是,您询问观察者模式。从GoF开始,观察者模式在以下情况下非常有用:

  1. 抽象有两个方面,一个依赖于另一个;
  2. 对一个对象的更改需要更改其他对象,并且您不知道需要更改多少个对象;或
  3. 对象应该能够在不假设这些对象是谁的情况下通知其他对象。
  4. 我不完全确定这些情况适用于此。第二种情况与您的问题有一些相似之处,但您知道需要改变什么以及如何改变。如果您正在进行的唯一更新是报告类型,则只需启用或禁用右侧下拉菜单即可。但是,您说其他下拉列表会相互影响,可能在“全部”选项中。即使在这种情况下,我也不确定Observer模式本身是最有帮助的。由于您使用SQL填充下拉列表,我猜您可能正在使用许多不同的存储过程(或即席查询),具体取决于您需要的参数。我建议的是每个下拉列表只有一个查询,明智地使用NULL。例如,要从其他值填充Block,您可能有:

    CREATE PROCEDURE GetBlocks
    (
        @SchemeTypeId INT NULL,
        @SchemeId INT NULL,
        @DistrictId INT NULL
    )
    AS
    SELECT b.BlockId, b.BlockName
    FROM   Blocks b
    INNER JOIN SchemeTypeBlocks stb ON b.BlockId = stb.BlockId
    INNER JOIN SchemeBlocks sb ON b.BlockId = sb.BlockId
    INNER JOIN DistrictBlocks db ON b.BlockId = db.BlockId
    WHERE  (@SchemeTypeId IS NULL OR stb.SchemeTypeId = @SchemeTypeId)
    AND    (@SchemeId IS NULL OR sb.SchemeId = @SchemeId)
    AND    (@DistrictId IS NULL OR db.DistrictId = @DistrictId)
    ORDER BY b.BlockName
    

    在不知道您的数据库的情况下,我不知道究竟会起什么作用,但我们的想法是,您只需将NULL传递给尚未选择的任何内容。这可能会稍微简化您的代码。

    如果这不能解答您的问题,请告诉我我可以澄清的内容。

答案 4 :(得分:1)

有一种简单的方法可以实现这一目标,请遵循以下方法: 首先,只需添加一个AjaxUpdatePanel ...然后在下拉菜单中将AutoPostBack属性设置为true, 进一步只需在OnSelectedIndexChanged事件上添加处理程序以启用第二次下拉..

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate><asp:DropDownList id="firstDrpDown" AutoPostBack="true"  
 OnSelectedIndexChanged="firstDropDown_SelectedIndexChanged"AppendDataBoundItems="true"
   name="firstDropDown" runat="server">

<asp:DropDownList id="scndDrpDown" **AutoPostBack="true"**  
OnSelectedIndexChanged="scndDropDown_SelectedIndexChanged" AppendDataBoundItems="true"   
name="scndDropDown" runat="server" > 

 </ContentTemplate>
  <asp:UpdatePanel>