【问题标题】:Some problems with GridView in webpart with multiple filters带有多个过滤器的 webpart 中的 GridView 的一些问题
【发布时间】:2010-04-12 13:59:14
【问题描述】:

我目前正在为 WSS 3.0 开发一个高度可配置的数据库查看器 webpart,我们将需要几个自定义共享点站点。提前为大量文字感到抱歉,但我担心有必要回顾整个问题。

作为背景信息并尽可能好地描述我的问题,我将首先告诉你 webpart 应该做什么:

基本上,webpart 包含一个 UpdatePanel,其中包含一个 GridView 和一个 SqlDataSource。数据源使用的选择查询可以通过 webbrowseable 属性设置,也可以从另一个 webpart 的使用者方法接收。 现在我想向 web 部件添加一个过滤功能,所以我想在标题行中为应该可过滤的每一列提供一个下拉列表。由于选择查询是完全动态的,而且我在设计时不知道哪些列可以过滤,所以我决定添加一个 webbrowseable 属性来包含一个带有过滤信息的 xml 格式的字符串。

所以我在 gridview 的 OnRowCreated 中添加了以下内容:

    void gridView_RowCreated(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.Header)
        {             
            for (int i = 0; i < e.Row.Cells.Count; i++)
            {
                if (e.Row.Cells[i].GetType() == typeof(DataControlFieldHeaderCell))
                {
                    string headerText = ((DataControlFieldHeaderCell)e.Row.Cells[i]).ContainingField.HeaderText;

                    // add sorting functionality
                    if (_allowSorting && !String.IsNullOrEmpty(headerText))
                    {
                        Label l = new Label();
                        l.Text = headerText;
                        l.ForeColor = Color.Blue;
                        l.Font.Bold = true;
                        l.ID = "Header" + i;
                        l.Attributes["title"] = "Sort by " + headerText;
                        l.Attributes["onmouseover"] = "this.style.cursor = 'pointer'; this.style.color = 'red'";
                        l.Attributes["onmouseout"] = "this.style.color = 'blue'";
                        l.Attributes["onclick"] = "__doPostBack('" + panel.UniqueID + "','SortBy$" + headerText + "');";
                        e.Row.Cells[i].Controls.Add(l);
                    }

                    // check if this column shall be filterable
                    if (!String.IsNullOrEmpty(filterXmlData))
                    {
                        XmlNode columnNode = GetColumnNode(headerText);

                        if (columnNode != null)
                        {
                            string dataValueField = columnNode.Attributes["DataValueField"] == null ? "" : columnNode.Attributes["DataValueField"].Value;
                            string filterQuery = columnNode.Attributes["FilterQuery"] == null ? "" : columnNode.Attributes["FilterQuery"].Value;

                            if (!String.IsNullOrEmpty(dataValueField) && !String.IsNullOrEmpty(filterQuery))
                            {
                                SqlDataSource ds = new SqlDataSource(_conStr, filterQuery);
                                DropDownList cbx = new DropDownList();
                                cbx.ID = "FilterCbx" + i;
                                cbx.Attributes["onchange"] = "__doPostBack('" + panel.UniqueID + "','SelectionChange$" + headerText + "$' + this.options[this.selectedIndex].value);";
                                cbx.Width = 150;
                                cbx.DataValueField = dataValueField;
                                cbx.DataSource = ds;

                                cbx.DataBound += new EventHandler(cbx_DataBound);
                                cbx.PreRender += new EventHandler(cbx_PreRender);
                                cbx.DataBind();

                                e.Row.Cells[i].Controls.Add(cbx);
                            }
                        }
                    }
                }
            }
        }
    }

GetColumnNode() 检查过滤器属性是否存在当前列的节点,其中包含有关 DropDownList 应绑定到的字段的信息,以及用于填充项目的查询。

在 cbx_PreRender() 中,我检查 ViewState 并选择一个项目以防回发。

在 cbx_DataBound() 中,我只是将工具提示添加到列表项,因为下拉列表具有固定宽度。

以前,我使用 DDL 的 AutoPostback 和 SelectedIndexChanged 来过滤网格,但令我失望的是,它并不总是被触发。现在我在 OnLoad 中检查 __EVENTTARGET 和 __EVENTARGUMENT 并在回发事件是由于 DDL 中的选择更改引起时调用一个函数:

    private void FilterSelectionChanged(string columnName, string selectedValue)
    {
        columnName = "[" + columnName + "]";
        if (selectedValue.IndexOf("--") < 0 ) // "-- All --" selected
        {
            if (filter.ContainsKey(columnName))
                filter[columnName] = "='" + selectedValue + "'";
            else
                filter.Add(columnName, "='" + selectedValue + "'");
        }
        else
        {
            filter.Remove(columnName);
        }

        gridView.PageIndex = 0;
    }

"filter" 是一个 HashTable,它存储在 ViewState 中用于持久化过滤器(在网络上的某个地方获得了这个示例,不记得在哪里)。

在 webpart 的 OnPreRender 中,我调用了一个函数,该函数读取 ViewState 并将 filterExpression 应用于数据源(如果有)。我想我必须把它放在这里,因为如果有另一个回发(例如用于排序),则不再应用过滤器。

    private void ApplyGridFilter()
    {
        string args = " ";
        int i = 0;

        foreach (object key in filter.Keys)
        {
            if (i == 0)
                args = key.ToString() + filter[key].ToString();
            else
                args += " AND " + key.ToString() + filter[key].ToString();

            i++;
        }

        dataSource.FilterExpression = args;
        ViewState.Add("FilterArgs", filter);
    }

    protected override void OnPreRender(EventArgs e)
    {
        EnsureChildControls();

        if (WebPartManager.DisplayMode.Name == "Edit")
        {
            errMsg = "Webpart in Edit mode...";
            return;
        }

        if (useWebPartConnection == true) // get select-query from consumer webpart
        {
            if (provider != null)
            {
                dataSource.SelectCommand = provider.strQuery;
            }
        }

        try
        {
            int currentPageIndex = gridView.PageIndex;

            if (!String.IsNullOrEmpty(m_SortExpression))
            {
                gridView.Sort("[" + m_SortExpression + "]", m_SortDirection);
            }
            gridView.PageIndex = currentPageIndex; // for some reason, the current pageindex resets after sorting
            ApplyGridFilter();
            gridView.DataBind();
        }
        catch (Exception ex)
        {
            Functions.ShowJavaScriptAlert(Page, ex.Message);
        }

        base.OnPreRender(e);
    }

所以我设置了 filterExpression 和调用 DataBind()。我不知道这是否可以在这个后期阶段.. 毕竟没有很多 asp.net 经验。如果有人可以提出更好的解决方案,请给我提示。

到目前为止,这一切都很好,除非我有两个或更多过滤器并将它们设置为返回零记录的组合。 Bam ... gridview 完全消失了 - 没有将过滤器改回来的可能性。所以我用谷歌搜索发现我必须子类化gridview才能始终显示标题行。我找到了this solution,并通过一些修改实现了它。

标题行得到显示,即使返回的结果不包含任何行,我也可以更改过滤器。但最后是我目前的问题:

当我设置了两个或多个返回零行的过滤器,并且我将一个过滤器更改回应该返回行的东西时,gridview 保持为空(尽管呈现了寻呼机)。我必须完全刷新页面才能重置过滤器。调试时,我可以在网格的重写 CreateChildControls 中看到,基本方法确实返回 > 0,但无论如何...... gridView.RowCount 在数据绑定后仍然为 0。有人知道这里出了什么问题吗?

【问题讨论】:

    标签: asp.net gridview drop-down-menu filter


    【解决方案1】:

    没关系,我自己找到的。错误在于我发布的链接中子类化gridview的实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-15
      • 2011-11-07
      • 1970-01-01
      • 2014-03-26
      • 2013-12-15
      • 2020-09-21
      • 1970-01-01
      相关资源
      最近更新 更多