Некоторые проблемы с GridView в веб-части с несколькими фильтрами - PullRequest
0 голосов
/ 12 апреля 2010

В настоящее время я работаю над настраиваемой веб-частью Просмотр базы данных для WSS 3.0, которая нам понадобится для нескольких настраиваемых сайтов sharepoint. Заранее извините за большую стену текста, но я боюсь, что необходимо вспомнить весь вопрос.

В качестве справочной информации и для того, чтобы как можно лучше описать мою проблему, я начну с рассказа о том, что должна делать веб-часть:

В основном веб-часть содержит UpdatePanel, которая содержит GridView и SqlDataSource. Запрос на выборку, который использует источник данных, может быть задан через веб-обозреваемые свойства или получен из потребительского метода из другой веб-части. Теперь я хотел добавить функцию фильтрации к веб-части, поэтому я хочу выпадающий список в заголовке для каждого столбца, который должен быть фильтруемым. Поскольку запрос на выборку является полностью динамическим, и я не знаю во время разработки, какие столбцы должны фильтроваться, я решил добавить свойство webbrowseable, чтобы оно содержало строку в формате XML с информацией фильтра.

Итак, я добавил следующее в OnRowCreated gridview:

    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 () я просто добавляю подсказки к элементам списка, поскольку выпадающий список имеет фиксированную ширину.

Ранее я использовал AutoPostback и SelectedIndexChanged из DDL для фильтрации сетки, но, к моему разочарованию, это не всегда срабатывало. Теперь я проверяю __EVENTTARGET и __EVENTARGUMENT в OnLoad и вызываю функцию, когда событие обратной передачи было связано с изменением выбора в 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;
    }

«фильтр» - это HashTable, который хранится во ViewState для сохранения фильтров (этот пример был где-то в сети, не помню где).

В 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. Если кто-то может предложить лучшее решение, пожалуйста, дайте мне подсказку.

Пока все это прекрасно работает, за исключением случаев, когда у меня есть два или более фильтров и я установил их в комбинацию, которая возвращает ноль записей. Бам ... gridview исчез, полностью - без возможности замены фильтров обратно. Так что я погуглил и обнаружил, что мне нужно создать подкласс gridview, чтобы всегда показывать заголовок. Я нашел это решение и реализовал его с некоторыми изменениями.

Отображается заголовок get, и я могу изменить фильтры, даже если возвращаемый результат не содержит строк. Но, наконец, к моей текущей проблеме:

Когда у меня установлено два или более фильтров, которые возвращают ноль строк, и я заменяю один фильтр на то, что должно возвращать строки, gridView остается пустым (хотя пейджер отображается). Я должен полностью обновить страницу, чтобы сбросить фильтры. При отладке я вижу в переопределенных CreateChildControls сетки, что базовый метод действительно возвращает> 0, но в любом случае ... gridView.RowCount остается 0 после привязки данных. У кого-нибудь есть идеи, что здесь происходит?

1 Ответ

0 голосов
/ 13 апреля 2010

Неважно, нашел это сам. Ошибка была в реализации подкласса сетки по ссылке, которую я разместил.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...