<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="gridBuildDynamic_test.aspx.cs" Inherits="gridBuildDynamic_test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"
http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div id="divDynamicGrid">
<asp:TextBox ID="txtOwnerID" runat="server"></asp:TextBox><asp:Button
ID="btnRefreshGrid" runat="server"
OnClick="btnRefreshGrid_Click" Text="Refresh Brands" /><br />
<asp
ropDownList ID="ddlBrands" runat="server">
</asp
ropDownList>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click"
Text="Bind" /><br />
<br />
<br />
<asp
ropDownList ID="ddlGridViews" runat="server"
OnSelectedIndexChanged="ddlGridViews_SelectedIndexChanged"
AutoPostBack="True" AppendDataBoundItems="True">
</asp
ropDownList>
<asp
ropDownList ID="ddlGridFieldGroups" runat="server"
AppendDataBoundItems="True" AutoPostBack="True"
OnSelectedIndexChanged="ddlGridFieldGroups_SelectedIndexChanged">
</asp
ropDownList>
<br />
<br />
<asp:GridView ID="gvDynamicGrid" runat="server"
AutoGenerateColumns="False" BackColor="LightGoldenrodYellow"
BorderColor="Tan" BorderWidth="1px" CellPadding="2" ForeColor="Black"
GridLines="None" DataKeyNames="Product_ID">
<FooterStyle BackColor="Tan" />
<PagerStyle BackColor="PaleGoldenrod" ForeColor="DarkSlateBlue"
HorizontalAlign="Center" />
<SelectedRowStyle BackColor="DarkSlateBlue"
ForeColor="GhostWhite" />
<HeaderStyle BackColor="Tan" Font-Bold="True" />
<AlternatingRowStyle BackColor="PaleGoldenrod" />
</asp:GridView>
<br />
<asp:Button ID="btnSaveAll" runat="server"
OnClick="btnSaveAll_Click" Text="Update Products" /><asp:Button
ID="btnCancel" runat="server" OnClick="btnCancel_Click"
Text="Cancel Changes" />
</div>
</form>
</body>
</html>
____________________________
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Reflection;
using ReplinkDotNet.Library;
public partial class gridBuildDynamic_test : System.Web.UI.Page
{
//All of the Objects and Collections in this page use the CSLA framework
standards
#region Load Dropdowns and Build/Bind Grid
protected void Page_Load(object sender, EventArgs e)
{
//If the user has chosen a GridFieldGroup, create the grid.
//Also re-create it upon postback
if (ddlGridFieldGroups.SelectedValue != "")
{
BuildGrid(ddlGridFieldGroups.SelectedValue);
}
if (!IsPostBack)
{
//This loads the GridViewList, just a dropdownlist to filter the
GridFieldGroups
//so our users don't have 100 items in their drop down
GridViewList gv = GridViewList.GetGridViewList();
ddlGridViews.DataSource = gv.BindableList;
ddlGridViews.DataValueField = "Value";
ddlGridViews.DataTextField = "Name";
ddlGridViews.DataBind();
}
}
protected void ddlGridViews_SelectedIndexChanged(object sender,
EventArgs e)
{
//When a GridView is selected the GridFieldGroups drop down is
populated
ddlGridFieldGroups.Items.Clear();
GridFieldGroupList gfg =
GridFieldGroupList.GetGridFieldGroupList(Convert.ToInt32(ddlGridViews.SelectedValue));
ddlGridFieldGroups.DataSource = gfg.BindableList;
ddlGridFieldGroups.DataValueField = "Value";
ddlGridFieldGroups.DataTextField = "Name";
ddlGridFieldGroups.DataBind();
}
protected void ddlGridFieldGroups_SelectedIndexChanged(object sender,
EventArgs e)
{
//When a new GridFieldGroup is selected, re-bind the data to the new
grid (which is generated dynamically in the Page_Load)
BindData();
}
protected void BuildGrid(string GridFieldGroupID)
{
//Build the GridView Based upon the selected GridFieldGroup
//Clear the existing columns
gvDynamicGrid.Columns.Clear();
TemplateField tf;
//This is a collection of DictionaryField Business Objects. Each
DictionaryField item represents a database
//field that will be bound to a GridView column. We iterate through
the DictionaryField objects, create the columns,
//which include databinding events (further down in the
gridColumnTemplateClass)
DictionaryFields dfs =
DictionaryFields.GetDictionaryFields(Convert.ToInt32(GridFieldGroupID));
foreach (DictionaryField df in dfs)
{
//Create a new TeamplateField and set the header
tf = new TemplateField();
tf.HeaderText = df.FieldName;
//Set the ItemTemplate to a new instance of the gridCOlumnTemplate
//We need to pass in the ListItemType, the field's DataType, and
the Field's Name
tf.ItemTemplate = new gridColumnTemplate(ListItemType.Item,
df.DataType, df.FieldName);
//Add the TemplateField to the Columns collection of the GridView
gvDynamicGrid.Columns.Add(tf);
}
//This is one extra TemplateField we append to the end of the grid
//If the user wants the Product deleted, they click the checkbox in
this column
//It gets added to every grouping of fields
tf = new TemplateField();
tf.HeaderText = "Delete?";
tf.ItemTemplate = new gridColumnTemplate(ListItemType.Item, "bit",
"toDelete");
gvDynamicGrid.Columns.Add(tf);
}
protected void BindData()
{
//This function retrieves a collection of Product Business Objects
//Then it binds this collection to the GridView
//The products contain all of the fields in the database
//**** ON OF OUR QUESTIONS IS HOW TO LAZY LOAD THE OBJECT ****
//First we check to see if the user has selected a Brand (a Brand is
what we use to retrive our collection of Products)
//If they have not, we hard code one in just for TESTING purposes only
//If they have, we use it to retrieve the selected products
Guid g;
if (ddlBrands.SelectedValue == "")
{
g = new Guid("{8F00A604-421E-4AEB-A853-35319B49E838}");
}
else
{
g = new Guid(ddlBrands.SelectedValue);
}
//Retritve the Products collection
Products ps = Products.GetProducts(g);
//Set the Datasource and Bind the Grid
gvDynamicGrid.DataSource = ps;
gvDynamicGrid.DataBind();
}
#endregion
#region gridColumnTemplate Class
public class gridColumnTemplate : IBindableTemplate
{
//This is our TemplateField Class
ListItemType _templateType;
string _fieldName;
string _dataType;
public gridColumnTemplate(ListItemType type, string dataType, string
fieldName)
{
_templateType = type;
_dataType = dataType;
_fieldName = fieldName;
}
public void InstantiateIn(System.Web.UI.Control container)
{
//This function Instantiates teh controls for our FieldTemplate
and includes DataBinding events
//There can be three different items returned
//1. A Textbox bound to an object property
//2. A Checkbox bound to an object property (if the datatype is
bit)
//3. An HTML Checkbox to delete items, it is NOT bound
HtmlInputCheckBox cbDelete;
CheckBox cb;
TextBox tb;
switch (_templateType)
{
case ListItemType.Item:
switch (_fieldName)
{
case "toDelete":
cbDelete = new HtmlInputCheckBox();
cbDelete.ID = "toDelete";
container.Controls.Add(cbDelete);
break;
default:
switch (_dataType)
{
case "bit":
cb = new CheckBox();
cb.ID = _fieldName;
cb.DataBinding += new
EventHandler(TemplateControl_DataBinding);
container.Controls.Add(cb);
break;
// There are going to be many more cases for
pct, money, dates, etc. But for now they'll all be straigh textboxes
default:
tb = new TextBox();
tb.ID = _fieldName;
tb.BackColor =
System.Drawing.Color.Transparent;
tb.BorderStyle = BorderStyle.None;
tb.DataBinding += new
EventHandler(TemplateControl_DataBinding);
container.Controls.Add(tb);
break;
}
break;
}
break;
}
}
public IOrderedDictionary ExtractValues(Control container)
{
//This allows us to retrieve our values
OrderedDictionary dict = new OrderedDictionary();
switch (_dataType)
{
case "bit":
bool bValue = ((CheckBox)container.Controls[0]).Checked;
dict.Add(this._fieldName, bValue);
break;
default:
string sValue = ((TextBox)container.Controls[0]).Text;
dict.Add(this._fieldName, sValue);
break;
}
return dict;
}
private void TemplateControl_DataBinding(object sender, EventArgs e)
{
//This is our DataBinding event
object databoundValue =
DataBinder.Eval(((IDataItemContainer)((Control)sender).NamingContainer).DataItem, _fieldName);
TextBox textBox = sender as TextBox;
if (textBox != null)
{
textBox.Text = databoundValue.ToString();
}
else
{
CheckBox checkBox = sender as CheckBox;
if (checkBox != null)
{
checkBox.Checked = (bool)databoundValue;
}
}
}
}
#endregion
#region BrandsBinding
protected void btnRefreshGrid_Click(object sender, EventArgs e)
{
//After a user enters an OwnerID they click this button to refresh
the Brands list
BindBrandList();
}
protected void BindBrandList()
{
//Brands is a collection of Brand Business Objects
Brands bnds;
bnds = Brands.GetBrands(txtOwnerID.Text);
//Set Data values and Bind to dropdownlist
ddlBrands.DataSource = bnds;
ddlBrands.DataTextField = "BrandName";
ddlBrands.DataValueField = "Brand_ID";
ddlBrands.DataBind();
}
protected void Button1_Click(object sender, EventArgs e)
{
//When the user selects a different brand they then select Bind to
rebind the grid
//Obviously this is just for testing, our user interface will not
require this button
BindData();
}
#endregion
#region Save and Cancel Changes
protected void btnSaveAll_Click(object sender, EventArgs e)
{
//This function iterates through the GridViewRows and saves teh
users changes
//**** THIS IS WHERE OUR MAIN ERROR IS ******
Product prd;
DictionaryFields dfs =
DictionaryFields.GetDictionaryFields(Convert.ToInt32(ddlGridFieldGroups.SelectedValue));
//Iterate through each row in the GridView
foreach (GridViewRow r in gvDynamicGrid.Rows)
{
//Retrive teh Product object using the Product_ID field
Guid id = new
Guid(Convert.ToString(gvDynamicGrid.DataKeys[r.RowIndex].Value));
prd = Product.GetProduct(id);
//Check the Delete HTML Checkbox
//*** THIS DOES NOT WORK ***
HtmlInputCheckBox cbDelete =
(HtmlInputCheckBox)r.FindControl("toDelete");
//If the user has checked Delete then delete the object from the
collection (and of course, from the database)
//*** THIS DOES NOT WORK ***
//Becuase the above line doesn't work we get the following error:
// "System.NullReferenceException: Object reference not set to
an instance of an object."
if (cbDelete.Checked)
{
//Mark the item as delete and save the change in the object
prd.Delete();
prd.Save();
}
else
{
//If Delete is not checked, update changes in each field
TextBox tb;
CheckBox cb;
//Iterate through the DictioaryFields collection retrieved
above
foreach (DictionaryField df in dfs)
{
//IF the datatype is a bit we need to update from a
Checkbox
if (df.DataType == "bit")
{
//*** THIS DOES NOT WORK ***
cb = (CheckBox)r.FindControl(df.FieldName);
//Use this function to set the Property value in the
object
//*** THIS DOES NOT WORK **
//Because the above line doesn't work we get the
following error here:
// "System.NullReferenceException: Object reference
not set to an instance of an object."
setProperty(prd, df.FieldName, cb.Checked);
}
else
{
//If the datatype is anything but a bit we need to
update from a TextBox
//*** THIS DOES NOT WORK ***
tb = (TextBox)r.FindControl(df.FieldName);
//Use this function to set the Property value in the
object
//*** THIS DOES NOT WORK **
//Because the above line doesn't work we get the
following error here:
// "System.NullReferenceException: Object reference
not set to an instance of an object."
setProperty(prd, df.FieldName, tb.Text);
}
}
//Save the changes to the Product Object
prd.Save();
}
}
//All of the changes have been made, Rebind the grid to the new data
BindData();
}
protected void btnCancel_Click(object sender, EventArgs e)
{
//To cancel all of the users changes we just need to Re-Bind the
grid without saving any changes
BindData();
}
public void setProperty(object obj, string field, object value)
{
//This function uses reflection to set the Object Property
//C# doesn't have an EVAL function like VB and our object don't
support
//Our objects do not support Object[PropertyName]=New value, only
Object.PropertyName=New value
//Therefore we need to use reflection. In VB we could use
EVAL("Object."+PropertyName+"=NewValue") but we are using C# obviously
PropertyInfo pi = obj.GetType().GetProperty(field);
pi.SetValue(obj, value, null);
}
#endregion
}