带有多个过滤器的webpart中的GridView的一些问题

时间:2010-04-12 13:59:15

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

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

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

基本上,webpart包含一个UpdatePanel,它包含一个GridView和一个SqlDataSource。 Datasource使用的select-query可以通过webbrowseable属性设置,也可以从另一个webpart的consumer方法接收。 现在我想为webpart添加一个过滤功能,所以我想在每个应该可过滤的列的headerrow中有一个下拉列表。由于select-query是完全动态的,我不知道在设计时哪些列可以过滤,我决定添加一个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()检查filter属性,如果当前列有一个节点,其中包含DropDownList应绑定到的Field的信息,以及填写项目的查询。

在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中以保存过滤器(在Web上的某处获取此示例,不记得在哪里)。

在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完全消失了 - 没有可能改变过滤器的可能性。所以我用Google搜索并发现我必须继承gridview才能始终显示headerrow。我找到this solution并对其进行了一些修改。

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

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

1 个答案:

答案 0 :(得分:0)

没关系,自己找到了。错误发生在我发布的链接的子类网格视图的实现中。