Hi all,
I have added templeted textbox column from code behind to my webgrid...
However if I do a paging or sorting I loose the text box and the column comes up like a regular column..
Any ideas on how to resolve this issue?
Thanks for your help..
Joel
Hello.
In order to properly create templated columns in code, you need to create a class that implements the ITemplate interface and then handle one method; namely the InstantiateIn method. This method is where you will add the controls to the CellItem. You also need to set the CellTemplate property on the column object to a new instance of your class that implements ITemplate. Thirdly, you need to handle the grids server side TemplatedColumnRestored event. Here is some code to demonstrate this. First, we add the templated column in InitializeLayout:
TemplatedColumn tc = new TemplatedColumn(true); tc.Key = "ImageButton"; tc.Header.Caption = "Image Button"; e.Layout.Bands[0].Columns.Add(tc); //Set the columns template to a new instance of the PlaceHolderTemplate class. tc.CellTemplate = new PlaceHolderTemplate();
Here is the PlaceHolderTemplate class. All I am doing is placing a standard ImageButton into the cell template, but the process is the same for other controls:
public class PlaceHolderTemplate : ITemplate { #region ITemplate Members void ITemplate.InstantiateIn(Control container) { CellItem ci = (CellItem)container; //Create a new instance of the image button, assign alternaten text, and add it to //the cell template. ImageButton ib = new ImageButton(); ib.EnableViewState = true; ci.Controls.Add(ib); } #endregion }
Here is the grids TemplatedColumnRestored event where you need to check the contents of the cell template on each postback:
if (((TemplatedColumn)e.Column).CellTemplate == null) { ((TemplatedColumn)e.Column).CellTemplate = new PlaceHolderTemplate(); }
Following these steps will ensure that your programmatically created templated columns will work and that the controls will be created on every postback.
Hello,
I'm following this example and I could create my custom ITemplate (I'm creating a DropDownList inside of it). The problem that I have is that I cannot unbind the SelectedValue and I'm not sure the problem is because after the TemplatedColumnRestored is called, the controls is recreated (new object).
Is there a way to get the selected value by the user?
Thanks in advance,
Charlie Duffy"]Hello.In order to properly create templated columns in code, you need to create a class that implements the ITemplate interface and then handle one method; namely the InstantiateIn method. This method is where you will add the controls to the CellItem. You also need to set the CellTemplate property on the column object to a new instance of your class that implements ITemplate. Thirdly, you need to handle the grids server side TemplatedColumnRestored event. Here is some code to demonstrate this. First, we add the templated column in InitializeLayout: TemplatedColumn tc = new TemplatedColumn(true); tc.Key = "ImageButton"; tc.Header.Caption = "Image Button"; e.Layout.Bands[0].Columns.Add(tc); //Set the columns template to a new instance of the PlaceHolderTemplate class. tc.CellTemplate = new PlaceHolderTemplate();Here is the PlaceHolderTemplate class. All I am doing is placing a standard ImageButton into the cell template, but the process is the same for other controls: public class PlaceHolderTemplate : ITemplate { #region ITemplate Members void ITemplate.InstantiateIn(Control container) { CellItem ci = (CellItem)container; //Create a new instance of the image button, assign alternaten text, and add it to //the cell template. ImageButton ib = new ImageButton(); ib.EnableViewState = true; ci.Controls.Add(ib); } #endregion } Here is the grids TemplatedColumnRestored event where you need to check the contents of the cell template on each postback: if (((TemplatedColumn)e.Column).CellTemplate == null) { ((TemplatedColumn)e.Column).CellTemplate = new PlaceHolderTemplate(); } Following these steps will ensure that your programmatically created templated columns will work and that the controls will be created on every postback.
If you want to capture the selected value in the drop down loist inside a cell template, the best way to do this would be to add a client side event that fires when the value is selected. Then, on the client, set the value of the grid cell to the value in the drop down. When that happens, the cell has a new value and you can handle the grids UpdateRow or UpdateRowBatch event. This way, handling the selection of new data in any of the drop downs is no different than handling any new value in any other cell.
The ITemplate class to add the drop down should look something like this. The important part is where we call ddl.Attributes.Add:
void ITemplate.InstantiateIn(Control container) { CellItem ci = (CellItem)container; if(ci.Cell.Column.Key == "CategoryID") { DropDownList ddl = new DropDownList(); ddl.ID = "DropDownList1"; ddl.EnableViewState = true; ddl.Attributes.Add("onchange", "ddl_SelectedItemChanged(this);"); ci.Controls.Add(ddl); } }
In the InitializeRow event, we will fill the drop down by calling the FillDropDownList method. This is my own method that I wrote to populate the drop down, but you could bind the drop down to any soruce you wanted:
TemplatedColumn tc = (TemplatedColumn)e.Row.Cells.FromKey("CategoryID").Column;CellItem ci = (CellItem)tc.CellItems[e.Row.Index];DropDownList ddl = (DropDownList)ci.FindControl("DropDownList1");FillDropDownList(ddl);
On the client, we can handle the grids client side InitializeLayout event and declare a global variable to hold the grids ID. We will also write the function to handle the drop down's onchange event:
var gridID;function UltraWebGrid1_InitializeLayoutHandler(gridName){ gridID = gridName;}function ddl_SelectedItemChanged(ddl){ var grid = igtbl_getGridById(gridID); var cell = grid.getActiveRow().getCellFromKey("CategoryID"); cell.setValue(ddl.value);}
As you can see, all we are doing is simply setting the value of the grids cell after the drop down value has changed. Now that we have set the cells value, we can handle UpdateRow, UpdateRowBatch, UpdateCell, or UpdateCellBatch normally and simply look at the new value of the cell like you would with any other update. The nice part about this approach is that we are not forcing the grid to post back every time a value in the drop down changes by setting AutoPostBack to true on the drop down. Here, we can select a value and edit other cells if we like by handlign UpdateRow or UpdateRowBatch. It's a nicer interface than performing a full page postback every time we select a value.
Let me know if you have any other questions.
Thanks a lot for your fast response Charlie!
Hi,
I'm having a similar issue where I have a table with a column with properties, a column with the current values of those properties and a third column where a new value could be entered. I need to display either a textbox or date time picker in the third column based on the required data type of the property. Each row could possibly have a different data type and therefore I believe the cell template needs to be created in the Initialize Row event. So I need to add the templated column in the Initialize layout event but create the cell template in the Initialize Row event. Does anyone know how to do this or have similar source code? Thanks
I have a similar example, but for some reason the image button command event I am creating does not fire on the initial page load, it causes a postback, and then after postback it fires correctly. Any help??
<igmisc:WebAsyncRefreshPanel LinkedRefreshControlID="xxx" ID="WebAsyncRefreshPanelControl" runat="server" Width="100%">
<asp:Label ID="lblErr1" runat="server" CssClass="error" />
<center>
<table cellpadding="2" cellspacing="1" border="0" width="725px">
<tr valign="top">
<td>
<igtbl:UltraWebGrid ID="UltraWebGrid1" runat="server" OnClickCellButton="UltraWebGrid1_OnClickCellButton">
<DisplayLayout Name="UltraWebGrid1" AllowSortingDefault="yes" HeaderClickActionDefault="SortSingle"
RowSelectorsDefault="No" SelectTypeRowDefault="Single" SelectTypeCellDefault="Single"
StationaryMargins="Header" TableLayout="Fixed" Version="4.00" />
</igtbl:UltraWebGrid>
</td>
</tr>
</table>
</center>
<igtxt:WebDateTimeEdit ID="WebDateTimeEdit1" runat="server" DataMode="EditModeText" />
<igcmbo:WebCombo ID="cmbReportSchFrequency" runat="server" Version="4.00" DataValueField="ID" DataTextField="Name" DisplayValue="Name" />
<igcmbo:WebCombo ID="cmbReportDay" runat="server" Version="4.00" DataValueField="ID" DataTextField="Name" DisplayValue="Name" />
</igmisc:WebAsyncRefreshPanel>
ReportSchedules rs;
private string ErrorMsg = "";
private int iTimeFormat;
{
try
//Authenticate the user for permission to this page
}
else
this.lblErr1.Visible = true;
Common.ZLog(System.Web.HttpContext.Current, ErrorMsg, ex);
InitializeComponent();
TemplatedColumn tc = new TemplatedColumn(true);
tc.SortIndicator = SortIndicator.Disabled;
e.Layout.Bands[0].Columns.Add(tc);
pt.Grid1 = UltraWebGrid1;
tc.CellTemplate = pt;
//Move the delete button to the leftmost column of the grid.
//Set up the blank new row for inserting a new time entry.
e.Layout.RowSelectorsDefault = RowSelectors.No;
//Hide the grid data we do not want to display.
e.Layout.Bands[0].Columns.FromKey("xxx").Hidden = true;
//Set Grid Header titles / Captions.
e.Layout.Bands[0].Columns.FromKey("xxx").Header.Caption = "Name";
e.Layout.Bands[0].Columns.FromKey("xxx").Header.Caption = "Last Updated";
e.Layout.Bands[0].Columns.FromKey("xxx").Header.Caption = "Frequency";
//Set Column Widths
e.Layout.Bands[0].Columns.FromKey("xxx").Width = new Unit("150px");
e.Layout.Bands[0].Columns.FromKey("xxx").Width = new Unit("100px");
e.Layout.Bands[0].Columns.FromKey("xxx").Format = "MM/dd/yyyy";
public class PlaceHolderTemplate : ITemplate
CellItem ci = (CellItem)container;
ib.CssClass = "pointer";
ib.CommandArgument = ci.Cell.Row.Index.ToString();
ib.Attributes.Add("onclick", "return confirm ('Delete this record?');");
ci.Controls.Add(ib);
UltraGridRow currentRow = Grid1.Rows[Val];
/// <summary>
/// This method ensures that the delete button is present after page postbacks.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
Fill_cmbs(cmbReportSchFrequency, Common.ReportFrequency());
iTimeFormat = _clsSecurity.TimeFormat;
this.WebDateTimeEdit1.DisplayModeFormat = sFormat;
LoadGrid();
UltraWebGrid1.DataSource = ds;
UltraWebGrid1.DataBind();
UltraWebGrid1.Columns.FromKey("Edit").Move(0);
UltraWebGrid1.Columns.FromKey("Edit").Type = ColumnType.Button;
UltraWebGrid1.Columns.FromKey("Edit").CellButtonDisplay = CellButtonDisplay.OnMouseEnter;
UltraWebGrid1.Columns.FromKey("Edit").CellButtonStyle.BorderWidth = new Unit("0px");
UltraWebGrid1.Columns.FromKey("Edit").Header.Caption = "Edt";
this.UltraWebGrid1.Bands[0].Columns.FromKey("xxx").EditorControlID = WebDateTimeEdit1.UniqueID;
this.UltraWebGrid1.Bands[0].Columns.FromKey("xxx").EditorControlID = cmbReportDay.UniqueID;
this.UltraWebGrid1.Bands[0].Columns.FromKey("xxx").DataType = "System.Int32";
this.UltraWebGrid1.Bands[0].Columns.FromKey("xxx").EditorControlID = cmbReportSchFrequency.UniqueID;
/// bind dataset to the web combo.
/// <param name="WC"> the web combo to bind</param>
/// <returns></returns>
WC.DataSource = dt;
WC.DataBind();
m.DisplayErrorMsg(ErrorMsg + ex.Message);
break;
//rs.Delete(sID);
//UltraWebGrid1.Rows.Remove(e.Cell.Row);
Hi All
I was following all the sugestion above, but I wanted to keep working in the client side instead of submmiting the page. I had the same problem with the "uwgContact_TemplateUpdateCellsHandler" because it was not triggered. The problem was mainly when i was changing the page index of the grid (all the values of the dropdownlist dessapear).
In the server side I could not manage to take the control inside the cell in order to be asigned again in the dropdownlist.
I found a solution using javascript, basecaly I am using a dropDownList template and everytime that I was changing the page of the grid I was loosing the values of the dropdownlist. My solution was taking a hidden column in order to save the value of the drodownlist and after i change the page of the grid i set again the value to the dropdownlis.... My javascript code below:
function warpAllocationDetails_RefreshComplete(oPanel){ var gridContacts = igtbl_getGridById("ctl00_cphReportManagerPages_wpAllocationDetails_uwgContact"); if (gridContacts != null) { var initialIndex = 0+((gridContacts.PageSize*gridContacts.CurrentPageIndex)-gridContacts.PageSize); var finalIndex = (gridContacts.PageSize*gridContacts.CurrentPageIndex); var realIndex = 0; for (i=initialIndex;i<finalIndex;i++) { var activeRow = gridContacts.Rows.getRow(realIndex); var profileIdCellObj = activeRow.getCell(15); var profileDescCellObj = activeRow.getCell(16); var ddlObj = document.getElementById("ctl00_cphReportManagerPages_wpAllocationDetails_uwgContact_ci_0_17_"+i+"_ddlProfileUserGrid"); if ((ddlObj != null) && (profileIdCellObj.getValue() != null)) { ddlObj.value = profileIdCellObj.getValue(); } realIndex = realIndex + 1; } } messageAlert();}function ddl_SelectedItemChanged(ddlObj){ var gridContacts = igtbl_getGridById("ctl00_cphReportManagerPages_wpAllocationDetails_uwgContact"); if (gridContacts == null) return; var activeCellDdl = gridContacts.getActiveCell(); var activeRow = gridContacts.getActiveRow(); var profileIdCellObj = activeRow.getCell(15); var profileDescCellObj = activeRow.getCell(16); profileIdCellObj.setValue(ddlObj.value,true); profileDescCellObj.setValue(ddlObj[ddlObj.selectedIndex].text,true); gridContacts.getActiveRow().setSelected(true);}
You can see that each dropDownList has a default id that is automatecaly generated using the index of the current Row. This is why I access each dropdownlist using a loop with a variable "i" :
"ctl00_cphReportManagerPages_wpAllocationDetails_uwgContact_ci_0_17_"+i+"_ddlProfileUserGrid"
The function "ddl_SelectedItemChanged(ddlObj)" is set for each dropdownlist in the template:
public class ddlProfileTemplate : ITemplate{ private DataSet ddlDs; public ddlProfileTemplate(DataSet aDataSet) { this.ddlDs = aDataSet; } void ITemplate.InstantiateIn(Control container) { CellItem ci = (CellItem)container; if (ci.Cell.Column.Key == "userProfile") { DropDownList ddl = new DropDownList(); ddl.ID = "ddlProfileUserGrid"; ddl.EnableViewState = true; if (this.ddlDs != null) { for (int i = 0; i < this.ddlDs.Tables[0].Rows.Count; i++) { ddl.Items.Add(new ListItem((string)this.ddlDs.Tables[0].Rows[i]["DESCRIPTION"], this.ddlDs.Tables[0].Rows[i]["A_PROFILE"].ToString())); } ddl.Items.Insert(0, new ListItem(null, "")); } ddl.Attributes.Add("onchange", "ddl_SelectedItemChanged(this);"); ci.Controls.Add(ddl); } }}
Hello t_val_u.
I would suugest that you go to http://www.Infragistics.com and hover the mouse over "Get Help" from the top toolbar. When the menu drops down, select "Ask For Help" and you can request more indepth help from Developer Support. There may be something wrong with your project that we just cant see her in the forums.
Hello Charlie,
thanks for your answer. I do create all needed events for the webgrid as you describe. But the TemplatedColumnRestored event is the only one that does not fire when I do a postback.
I can not add the event directly in the html, because I need to create everything from scratch in runtime. The webgrid and all needed events need to be created programmatically.
I found articles about how to create a webgrid and a TemplatedColumn programmatically. I know how to add event handlers programmatically. But maybe I do this in the wrong order or at the wrong page events.
Is there a best practice article or something about how to do all this?
Thank you.