J
Jay Walker
I created a custom DataGridColumn based on Marcie Robillard's MSDN
Article:
Creating Custom Columns for the ASP.NET Datagrid
http://msdn.microsoft.com/library/d...y/en-us/dnaspp/html/creatingcustomcolumns.asp
The problem I am having is that the data in the custom datagridcolumn
is not saved to viewstate and after postback, the column does not
contain data.
Any idea's?
I simplified the code so that the error is easy to reproduce.
Here is the code: (notice that the CustomImage that is standalone on
the page and the CustomImage that is embedded in a template column are
visible after postback.)
I can send a zip file of the project on request.
-=-=-=-=- CustomColumn.cs (begin) -=-=-=-=-
using System;
using System.Data;
using System.Web.UI.WebControls;
using System.Web.UI;
namespace PostbackError
{
public class CustomColumn : System.Web.UI.WebControls.DataGridColumn
{
public override void
InitializeCell(System.Web.UI.WebControls.TableCell cell, int
columnIndex, System.Web.UI.WebControls.ListItemType itemType)
{
//if the grid is using sorting, the the header will contain a
DataGridLinkButton
//the functionality is set by the base class initializecell.
base.InitializeCell (cell, columnIndex, itemType);
switch (itemType)
{
case ListItemType.Item:
case ListItemType.AlternatingItem:
cell.DataBinding += new EventHandler(OnDataBinding);
break;
}}
private void OnDataBinding(object sender, EventArgs e)
{
TableCell cell = sender as TableCell;
DataGridItem dgi = cell.NamingContainer as DataGridItem;
DataRowView drv = dgi.DataItem as DataRowView;
//hardcoded for this example
string image = "arrow.gif";
if (image.Length == 0)
return;
CustomImage ri = new CustomImage();
cell.Controls.Add(ri);
TrackViewState();
string tooltip = "Help";
ri.ImageUrl = image;
ri.ToolTip = tooltip;
}}}
-=-=-=-=- CustomColumn.cs (end) -=-=-=-=-
-=-=-=-=- CustomImage.cs (begin) -=-=-=-=-
using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.Design;
namespace PostbackError
{
public class CustomImage : System.Web.UI.WebControls.Image
{
private string _imagePath = string.Empty;
public CustomImage():base()
{
_imagePath = string.Empty;
}
[
Browsable(true),
Category("Appearance"),
Description("Image to be displayed when the mouse is not over the
image")
]
public new string ImageUrl
{
get { return (string)ViewState["riImageUrl"]; }
set { ViewState["riImageUrl"] = value; }
}
[
Browsable(true),
Category("Appearance"),
Description("Image to be displayed when the mouse is over the
image")
]
public string MouseOverImageUrl
{
get { return (string)ViewState["MouseOverImageUrl"]; }
set { ViewState["MouseOverImageUrl"] = value; }
}
[
Browsable(true),
Category("Navigation"),
Description("The url to navigate to")
]
public string NavigateUrl
{
get { return (string)ViewState["NavigateUrl"]; }
set { ViewState["NavigateUrl"] = value; }
}
[
Browsable(true),
Category("Appearance"),
DefaultValue(true),
Description("Use a MouseOver Image derived from the Image name.
(i.e. image.gif -> image_ovr.gif)")
]
public bool UseMouseOverImage
{
get
{
string property = "UseMouseOverImage";
if (ViewState[property] == null)
{
object obj = _GetDefaultValue(property);
if (obj != null)
ViewState[property] = (bool)obj;
}
return (bool)ViewState[property];
}
set { ViewState["UseMouseOverImage"] = value; }
}
override protected void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string s = base.ImageUrl;
base.ImageUrl = _imagePath + ImageUrl;
s = base.ImageUrl;
string mouseOver = _GetImageMouseOver();
if (mouseOver != null && UseMouseOverImage)
{
Attributes.Add("onmouseover", "this.src='" + _imagePath +
mouseOver + "'");
Attributes.Add("onmouseout", "this.src='" + _imagePath + ImageUrl
+ "'");
}
}
/// <summary>
/// Render this control to the output parameter specified.
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void Render(HtmlTextWriter output)
{
bool bWriteAnchor = NavigateUrl != null && NavigateUrl.Length > 0;
string s1 = base.ImageUrl;
base.ImageUrl = _imagePath + ImageUrl;
StringWriter sw = new StringWriter();
HtmlTextWriter buffer = new HtmlTextWriter(sw);
if (bWriteAnchor)
{
buffer.AddAttribute(HtmlTextWriterAttribute.Href, NavigateUrl);
buffer.RenderBeginTag(HtmlTextWriterTag.A);
}
base.Render(buffer);
if (bWriteAnchor)
buffer.RenderEndTag();
string s = sw.ToString();
output.Write(s);
}
private object _GetDefaultValue(string propertyName)
{
System.ComponentModel.AttributeCollection attributes =
TypeDescriptor.GetProperties(this)[propertyName].Attributes;
DefaultValueAttribute myAttribute =
(DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
if (myAttribute != null)
return myAttribute.Value;
else
return null;
}
private string _GetImageMouseOver()
{
if (MouseOverImageUrl != null) return MouseOverImageUrl;
StringBuilder sb = new StringBuilder();
Regex re = new Regex(@"\.");
//Image should be like "media.gif" over image should be
"media_ovr.gif"
//and have a part left and right of the period
//if the entry is not in this format, then the entry is invalid
//so return null
if (ImageUrl == null) return null;
string[] sa = re.Split(ImageUrl);
if (sa.Length != 2) return null;
return sa[0] + "_ovr." + sa[1];
}
}
public class CustomImageDesigner:ControlDesigner
{
public override string GetDesignTimeHtml( )
{
return "<h6>" + this.ID + "</h6>";
}
}
}
-=-=-=-=- CustomImage.cs (end) -=-=-=-=-
-=-=-=-=- WebForm1.aspx (begin) -=-=-=-=-
<%@ Register TagPrefix="cust" Namespace="PostbackError"
Assembly="PostbackError" %>
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs"
AutoEventWireup="false" Inherits="PostbackError.WebForm1"
trace="true"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<br>
<cust:CustomImage id="ciTest" runat="server" ImageUrl="arrow.gif"
Border="1" />
<br>
<br>
<aspataGrid id="DataGrid1" runat="server" CellSpacing="1"
CellPadding="0" GridLines="None" AutoGenerateColumns="False"
AllowSorting="True" Width="100%">
<Columns>
<asp:TemplateColumn>
<HeaderTemplate>
<asp:CheckBox id="ckSelectAll" runat="server"
AutoPostBack="false" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox id="ckSelect" runat="server" AutoPostBack="false"
/>
</ItemTemplate>
</asp:TemplateColumn>
<cust:CustomColumn HeaderText="L" ItemStyle-BackColor="#ff0000"/>
<asp:TemplateColumn>
<ItemTemplate>
<cust:CustomImage id="ciGridImage" runat="server"
ImageUrl="arrow.gif" Border="1" />
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn DataField="col1" HeaderText="Col1">
<ItemStyle HorizontalAlign="Left" />
</asp:BoundColumn>
<asp:BoundColumn DataField="col2" HeaderText="Col2">
<ItemStyle HorizontalAlign="Left" />
</asp:BoundColumn>
</Columns>
</aspataGrid>
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
</form>
</body>
</HTML>
-=-=-=-=- WebForm1.aspx (end) -=-=-=-=-
-=-=-=-=- WebForm1.aspx.cs (begin) -=-=-=-=-
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace PostbackError
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button Button1;
protected PostbackError.CustomImage ciTest;
protected System.Web.UI.WebControls.DataGrid DataGrid1;
ICollection CreateDataSource()
{
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add(new DataColumn("col1", typeof(Int32)));
dt.Columns.Add(new DataColumn("col2", typeof(string)));
for (int i = 0; i < 5; i++)
{
dr = dt.NewRow();
dr[0] = i;
dr[1] = "Item " + i.ToString();
dt.Rows.Add(dr);
}
DataView dv = new DataView(dt);
return dv;
}
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
// Load this data only once.
DataGrid1.DataSource= CreateDataSource();
DataGrid1.DataBind();
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
-=-=-=-=- WebForm1.aspx.cs (end) -=-=-=-=-
Article:
Creating Custom Columns for the ASP.NET Datagrid
http://msdn.microsoft.com/library/d...y/en-us/dnaspp/html/creatingcustomcolumns.asp
The problem I am having is that the data in the custom datagridcolumn
is not saved to viewstate and after postback, the column does not
contain data.
Any idea's?
I simplified the code so that the error is easy to reproduce.
Here is the code: (notice that the CustomImage that is standalone on
the page and the CustomImage that is embedded in a template column are
visible after postback.)
I can send a zip file of the project on request.
-=-=-=-=- CustomColumn.cs (begin) -=-=-=-=-
using System;
using System.Data;
using System.Web.UI.WebControls;
using System.Web.UI;
namespace PostbackError
{
public class CustomColumn : System.Web.UI.WebControls.DataGridColumn
{
public override void
InitializeCell(System.Web.UI.WebControls.TableCell cell, int
columnIndex, System.Web.UI.WebControls.ListItemType itemType)
{
//if the grid is using sorting, the the header will contain a
DataGridLinkButton
//the functionality is set by the base class initializecell.
base.InitializeCell (cell, columnIndex, itemType);
switch (itemType)
{
case ListItemType.Item:
case ListItemType.AlternatingItem:
cell.DataBinding += new EventHandler(OnDataBinding);
break;
}}
private void OnDataBinding(object sender, EventArgs e)
{
TableCell cell = sender as TableCell;
DataGridItem dgi = cell.NamingContainer as DataGridItem;
DataRowView drv = dgi.DataItem as DataRowView;
//hardcoded for this example
string image = "arrow.gif";
if (image.Length == 0)
return;
CustomImage ri = new CustomImage();
cell.Controls.Add(ri);
TrackViewState();
string tooltip = "Help";
ri.ImageUrl = image;
ri.ToolTip = tooltip;
}}}
-=-=-=-=- CustomColumn.cs (end) -=-=-=-=-
-=-=-=-=- CustomImage.cs (begin) -=-=-=-=-
using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Web.UI.Design;
namespace PostbackError
{
public class CustomImage : System.Web.UI.WebControls.Image
{
private string _imagePath = string.Empty;
public CustomImage():base()
{
_imagePath = string.Empty;
}
[
Browsable(true),
Category("Appearance"),
Description("Image to be displayed when the mouse is not over the
image")
]
public new string ImageUrl
{
get { return (string)ViewState["riImageUrl"]; }
set { ViewState["riImageUrl"] = value; }
}
[
Browsable(true),
Category("Appearance"),
Description("Image to be displayed when the mouse is over the
image")
]
public string MouseOverImageUrl
{
get { return (string)ViewState["MouseOverImageUrl"]; }
set { ViewState["MouseOverImageUrl"] = value; }
}
[
Browsable(true),
Category("Navigation"),
Description("The url to navigate to")
]
public string NavigateUrl
{
get { return (string)ViewState["NavigateUrl"]; }
set { ViewState["NavigateUrl"] = value; }
}
[
Browsable(true),
Category("Appearance"),
DefaultValue(true),
Description("Use a MouseOver Image derived from the Image name.
(i.e. image.gif -> image_ovr.gif)")
]
public bool UseMouseOverImage
{
get
{
string property = "UseMouseOverImage";
if (ViewState[property] == null)
{
object obj = _GetDefaultValue(property);
if (obj != null)
ViewState[property] = (bool)obj;
}
return (bool)ViewState[property];
}
set { ViewState["UseMouseOverImage"] = value; }
}
override protected void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
string s = base.ImageUrl;
base.ImageUrl = _imagePath + ImageUrl;
s = base.ImageUrl;
string mouseOver = _GetImageMouseOver();
if (mouseOver != null && UseMouseOverImage)
{
Attributes.Add("onmouseover", "this.src='" + _imagePath +
mouseOver + "'");
Attributes.Add("onmouseout", "this.src='" + _imagePath + ImageUrl
+ "'");
}
}
/// <summary>
/// Render this control to the output parameter specified.
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void Render(HtmlTextWriter output)
{
bool bWriteAnchor = NavigateUrl != null && NavigateUrl.Length > 0;
string s1 = base.ImageUrl;
base.ImageUrl = _imagePath + ImageUrl;
StringWriter sw = new StringWriter();
HtmlTextWriter buffer = new HtmlTextWriter(sw);
if (bWriteAnchor)
{
buffer.AddAttribute(HtmlTextWriterAttribute.Href, NavigateUrl);
buffer.RenderBeginTag(HtmlTextWriterTag.A);
}
base.Render(buffer);
if (bWriteAnchor)
buffer.RenderEndTag();
string s = sw.ToString();
output.Write(s);
}
private object _GetDefaultValue(string propertyName)
{
System.ComponentModel.AttributeCollection attributes =
TypeDescriptor.GetProperties(this)[propertyName].Attributes;
DefaultValueAttribute myAttribute =
(DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
if (myAttribute != null)
return myAttribute.Value;
else
return null;
}
private string _GetImageMouseOver()
{
if (MouseOverImageUrl != null) return MouseOverImageUrl;
StringBuilder sb = new StringBuilder();
Regex re = new Regex(@"\.");
//Image should be like "media.gif" over image should be
"media_ovr.gif"
//and have a part left and right of the period
//if the entry is not in this format, then the entry is invalid
//so return null
if (ImageUrl == null) return null;
string[] sa = re.Split(ImageUrl);
if (sa.Length != 2) return null;
return sa[0] + "_ovr." + sa[1];
}
}
public class CustomImageDesigner:ControlDesigner
{
public override string GetDesignTimeHtml( )
{
return "<h6>" + this.ID + "</h6>";
}
}
}
-=-=-=-=- CustomImage.cs (end) -=-=-=-=-
-=-=-=-=- WebForm1.aspx (begin) -=-=-=-=-
<%@ Register TagPrefix="cust" Namespace="PostbackError"
Assembly="PostbackError" %>
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs"
AutoEventWireup="false" Inherits="PostbackError.WebForm1"
trace="true"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<br>
<cust:CustomImage id="ciTest" runat="server" ImageUrl="arrow.gif"
Border="1" />
<br>
<br>
<aspataGrid id="DataGrid1" runat="server" CellSpacing="1"
CellPadding="0" GridLines="None" AutoGenerateColumns="False"
AllowSorting="True" Width="100%">
<Columns>
<asp:TemplateColumn>
<HeaderTemplate>
<asp:CheckBox id="ckSelectAll" runat="server"
AutoPostBack="false" />
</HeaderTemplate>
<ItemTemplate>
<asp:CheckBox id="ckSelect" runat="server" AutoPostBack="false"
/>
</ItemTemplate>
</asp:TemplateColumn>
<cust:CustomColumn HeaderText="L" ItemStyle-BackColor="#ff0000"/>
<asp:TemplateColumn>
<ItemTemplate>
<cust:CustomImage id="ciGridImage" runat="server"
ImageUrl="arrow.gif" Border="1" />
</ItemTemplate>
</asp:TemplateColumn>
<asp:BoundColumn DataField="col1" HeaderText="Col1">
<ItemStyle HorizontalAlign="Left" />
</asp:BoundColumn>
<asp:BoundColumn DataField="col2" HeaderText="Col2">
<ItemStyle HorizontalAlign="Left" />
</asp:BoundColumn>
</Columns>
</aspataGrid>
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
</form>
</body>
</HTML>
-=-=-=-=- WebForm1.aspx (end) -=-=-=-=-
-=-=-=-=- WebForm1.aspx.cs (begin) -=-=-=-=-
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace PostbackError
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button Button1;
protected PostbackError.CustomImage ciTest;
protected System.Web.UI.WebControls.DataGrid DataGrid1;
ICollection CreateDataSource()
{
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add(new DataColumn("col1", typeof(Int32)));
dt.Columns.Add(new DataColumn("col2", typeof(string)));
for (int i = 0; i < 5; i++)
{
dr = dt.NewRow();
dr[0] = i;
dr[1] = "Item " + i.ToString();
dt.Rows.Add(dr);
}
DataView dv = new DataView(dt);
return dv;
}
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
// Load this data only once.
DataGrid1.DataSource= CreateDataSource();
DataGrid1.DataBind();
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
-=-=-=-=- WebForm1.aspx.cs (end) -=-=-=-=-