我目前正在开发一个高度可配置的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。任何人都知道这里出了什么问题?
答案 0 :(得分:0)
没关系,自己找到了。错误发生在我发布的链接的子类网格视图的实现中。