Object and nested datalists - asp.net

I am having trouble displaying my object in a datalist.
My object loks like this:
public class Course
{
private string courseName;
private DateTime[] courseDates;
public string CourseName
{
get { return courseName; }
set { courseName = value; }
}
public DateTime[] CourseDates
{
get { return courseDates; }
set {
foreach (DateTime dt in courseDates)
{
if (dt < DateTime.Now)
throw new Exception("The date of the course has to be after todays date.");
}
courseDates = value; }
}
public Course(string _courseName, DateTime[] _courseDates)
{
courseName = _courseName;
courseDates = _courseDates;
}
}
When I try to display it in a datalist the name of the course looks ok. But The dates are not shown.
So I was thinking I needed a nested datalist but then I don't know how to fill the second datalist with the dates in the object.

I've show two solutions:
<asp:DataList ID="DataList1" runat="server"
onitemdatabound="DataList1_ItemDataBound">
<ItemTemplate>
<td><%# DataBinder.Eval(Container.DataItem, "CourseName")%></td>
<td><%# RenderDates( DataBinder.Eval(Container.DataItem, "CourseDates"))%></td>
<td>
<asp:DataList ID="DateList" runat="server">
<ItemTemplate>
<td><%# Container.DataItem%></td>
</ItemTemplate>
</asp:DataList>
</td>
</ItemTemplate>
</asp:DataList>
and
public string RenderDates(object dates)
{
DateTime[] ds = dates as DateTime[];
StringBuilder sb = new StringBuilder();
if( ds != null && ds.Length > 0)
{
sb.Append(ds[0]);
for (int i = 1; i < ds.Length; i++)
{
sb.AppendFormat(" - {0}", ds[i]);
}
}
return sb.ToString();
}
protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)
{
DataListItem item = e.Item;
if ((item.ItemType == ListItemType.Item) ||
(item.ItemType == ListItemType.AlternatingItem))
{
var innerList= (DataList)item.FindControl("DateList");
innerList.DataSource = ((Course) item.DataItem).CourseDates;
innerList.DataBind();
}
}

Related

ASP.NET GridView RowDataBound TemplateField FindControl is null after invalid data entered

I am having trouble with my GridView RowDataBound event after I click on Save to save the data to the database.
I have a grid with 5 columns: Tag Name, Current Timestamp, Current Value, New Date, New Value.
The idea is the user will enter into the New Date/New Value to update the data in the database. The Current Timestamp and Current Value are what is already stored in the database.
I use a JQuery editor to enter the date.
When I click on Save, I have server side validation in place to check the entered values. If the data is valid, a message under the text in the New Value column is displayed to indicate this. If the validation fails, then a message in the New Value column is displayed.
New Date and New Value columns are TemplateField's. The New Value TemplateField contains a panel with two labels - one for OK status and the other for error.
The error occurs in MyDataGrid_RowDataBound when I call any e.Row.FindControl(...) which is triggered from the Save button click when I rebind.
It works ok if a valid value has been entered but if an invalid value is entered then it errors. In order to simplify the scenario, enter 100 for a valid value and anything else for an invalid.
This WebForm has been the trouble of my life. Maybe I shouldn't have used a GridView.
Anyway, I would appreciate any help here to identify the issue. And maybe a better approach to the form code.
I've took the code from my solution and moved it into a standalone solution to reproduce the issue. I've removed the database access and populated a datastructure. This is only ever done (once) in the Page Load when the page is initially loaded.
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link rel="stylesheet" href="Styles/jquery-ui-timepicker-addon.css" />
<link rel="stylesheet" href="Styles/jquery-ui-1.10.1.custom.css" />
<link rel="stylesheet" href="Styles/jquery-ui-1.10.1.custom.min.css" />
<script src="Scripts/jquery-1.9.1.js"></script>
<script src="Scripts/jquery-ui-1.10.1.custom.js"></script>
<script src="Scripts/jquery-ui-1.10.1.custom.min.js"></script>
<script src="Scripts/jquery-ui-timepicker-addon.js"></script>
</head>
<body>
<script type="text/javascript">
/** Disable backkey */
$(document).unbind('keydown').bind('keydown', function (event) {
var doPrevent = false;
if (event.keyCode === 8) {
var d = event.srcElement || event.target;
if ((d.tagName.toUpperCase() === 'INPUT' && (d.type.toUpperCase() === 'TEXT' || d.type.toUpperCase() === 'PASSWORD' || d.type.toUpperCase() === 'FILE'))
|| d.tagName.toUpperCase() === 'TEXTAREA') {
doPrevent = d.readOnly || d.disabled;
} else {
doPrevent = true;
}
}
if (doPrevent) {
event.preventDefault();
}
});
$(function () {
$(".datetimepicker").datetimepicker({
changeMonth: true,
changeYear: true
});
});
$(function () {
$(".datepicker").datepicker({
changeMonth: true,
changeYear: true
});
});
$(function () {
$(".timepicker").timepicker({ showTimezone: false });
});
</script>
<form id="form1" runat="server">
<div>
<asp:GridView ID="MyDataGrid" runat="server"
EnableModelValidation="True"
DataKeyNames="Id"
AutoGenerateColumns="False"
AutoGenerateSelectButton="False"
EmptyDataText="There is no plant data configured."
OnRowDataBound="MyDataGrid_RowDataBound">
<Columns>
<asp:BoundField DataField="Name" SortExpression="Name" HeaderText="Tag Name"></asp:BoundField>
<asp:BoundField DataField="Date" SortExpression="Date" HeaderText="Current Timestamp"></asp:BoundField>
<asp:BoundField DataField="Value" SortExpression="Value" HeaderText="Current Value"></asp:BoundField>
<asp:TemplateField HeaderText="New Date<BR/>MM/DD/YYYY HH:MM">
<ItemTemplate>
<asp:TextBox ID="txtNewDate" runat="server" CssClass="datetimepicker"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="New Value">
<ItemTemplate>
<asp:TextBox ID="txtNewValue" runat="server"></asp:TextBox>
<asp:Panel ID="ErrorPanel" runat="server">
<br />
<asp:Label ID="lblError" runat="server" ForeColor="Red"></asp:Label>
<asp:Label ID="lblStatus" runat="server" ForeColor="#66cc00"></asp:Label>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="SaveButton" runat="server"
Text="Save Values"
ToolTip="Save the current changes."
OnClick="SaveButton_Click" />
</div>
</form>
</body>
</html>
Code Behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
private const int COL_NEW_DATE = 3;
private const int COL_NEW_VALUE = 4;
bool canEdit = true;
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
PopulateDataGrid();
}
}
private void PopulateDataGrid()
{
// this is where i load from the database
List<RowData> data = new List<RowData>() {
new RowData() { Date = new DateTime(2000,1,1), Editable = true, Name = "Data Item 1", Value = 100.0 },
new RowData() { Date = new DateTime(2000,1,1), Editable = false, Name = "Data Item 2", Value = 120.0 },
new RowData() { Date = new DateTime(2000,1,1), Editable = true, Name = "Data Item 3", Value = 19.0 }
};
this.MyDataGrid.DataSource = data;
this.MyDataGrid.DataBind();
ViewState["GridData"] = this.MyDataGrid.DataSource;
}
private void SaveData()
{
for (int i = Page.Validators.Count - 1; i >= 0; i--)
Page.Validators.Remove(Page.Validators[i]);
ValidateData();
List<RowData> rowDataList = (List<RowData>)ViewState["GridData"];
if (this.IsValid)
{
foreach (GridViewRow row in this.MyDataGrid.Rows)
{
if (row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow && row.Enabled)
{
RowData dataItem = rowDataList[row.DataItemIndex];
var txtNewValue = row.Cells[COL_NEW_VALUE].FindControl("txtNewValue") as TextBox;
var txtNewDate = row.Cells[COL_NEW_DATE].FindControl("txtNewDate") as TextBox;
if (dataItem != null && txtNewDate != null && txtNewValue != null && !string.IsNullOrEmpty(txtNewValue.Text) && !string.IsNullOrEmpty(txtNewDate.Text))
{
var newValue = double.Parse(txtNewValue.Text);
var newDate = DateTime.Parse(txtNewDate.Text);
dataItem.InfoText = "Value written successfully for " + txtNewDate.Text;
dataItem.ErrorText = string.Empty;
dataItem.EnteredDateCache = string.Empty;
dataItem.EnteredValueCache = string.Empty;
if ((dataItem.Date.HasValue && DateTime.Compare(newDate, dataItem.Date.Value) >= 0) || !dataItem.Date.HasValue)
{
dataItem.Date = newDate;
dataItem.Value = newValue;
}
}
}
}
// save any outstanding changes if valid removed from demo
}
ViewState["GridData"] = rowDataList;
}
private void ValidateData()
{
List<RowData> rowDataList = (List<RowData>)ViewState["GridData"];
foreach (GridViewRow row in this.MyDataGrid.Rows)
{
if (row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow && row.Enabled)
ValidateDataRow(rowDataList, row);
}
}
private void ValidateDataRow(List<RowData> rowDataList, GridViewRow gridViewRow)
{
RowData rowData = rowDataList[gridViewRow.DataItemIndex];
bool valueOK = false;
var txtNewValue = gridViewRow.Cells[COL_NEW_VALUE].FindControl("txtNewValue") as TextBox;
var txtNewDate = gridViewRow.Cells[COL_NEW_DATE].FindControl("txtNewDate") as TextBox;
var labelError = gridViewRow.Cells[COL_NEW_VALUE].FindControl("lblError") as Label;
var labelInfo = gridViewRow.Cells[COL_NEW_VALUE].FindControl("lblStatus") as Label;
labelInfo.Text = string.Empty;
labelError.Text = string.Empty;
rowData.InfoText = string.Empty;
rowData.ErrorText = string.Empty;
rowData.EnteredDateCache = txtNewDate.Text;
rowData.EnteredValueCache = txtNewValue.Text;
if (rowData != null && (!string.IsNullOrEmpty(txtNewValue.Text) || !string.IsNullOrEmpty(txtNewDate.Text)))
{
if (!txtNewValue.Text.IsNumber())
{
rowData.ErrorText = rowData.Name + " must be a number.";
AddCustomValidatorForCell(rowData.ErrorText, gridViewRow, 4);
}
else
{
if (txtNewValue.Text != "100")
{
rowData.ErrorText = rowData.Name + " is invalid.";
AddCustomValidatorForCell(rowData.ErrorText, gridViewRow, 4);
}
else
{
valueOK = true;
}
}
}
}
private void AddCustomValidatorForCell(string errorMessage, GridViewRow gridViewRow, int cellIndex)
{
var labelError = gridViewRow.Cells[cellIndex].FindControl("lblError") as Label;
var divInfoError = gridViewRow.Cells[cellIndex].FindControl("ErrorPanel") as Panel;
labelError.Text = errorMessage;
labelError.ToolTip = errorMessage;
labelError.Attributes.Add("style", "color: red;");
CustomValidator validatePower = new CustomValidator()
{
IsValid = false,
ErrorMessage = errorMessage,
EnableViewState = false,
};
Page.Validators.Add(validatePower);
}
protected void SaveButton_Click(object sender, EventArgs e)
{
SaveData();
this.MyDataGrid.DataSource = ViewState["GridData"];
this.MyDataGrid.DataBind();
}
protected void MyDataGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
{
var rowData = e.Row.DataItem as RowData;
if (rowData != null)
{
DataControlFieldCell txtNewDate = (DataControlFieldCell)e.Row.Cells[COL_NEW_DATE];
DataControlFieldCell txtNewValue = (DataControlFieldCell)e.Row.Cells[COL_NEW_VALUE];
e.Row.Cells[1].Text = rowData.Date.HasValue ? rowData.Date.ToString() : string.Empty;
e.Row.Cells[2].Text = rowData.Value.HasValue ? rowData.Value.Value.ToString() : string.Empty;
txtNewValue.Enabled = txtNewDate.Enabled = (canEdit & rowData.Editable);
if (!string.IsNullOrEmpty(rowData.EnteredDateCache))
txtNewDate.Text = rowData.EnteredDateCache;
if (!string.IsNullOrEmpty(rowData.EnteredValueCache))
txtNewValue.Text = rowData.EnteredValueCache;
(e.Row.FindControl("lblStatus") as Label).Text = rowData.InfoText;
(e.Row.FindControl("lblError") as Label).Text = rowData.ErrorText;
//(e.Row.FindControl("ErrorPanel") as Panel).Visible = (!string.IsNullOrEmpty(rowData.InfoText) || !string.IsNullOrEmpty(rowData.ErrorText));
}
}
}
[Serializable()]
private class RowData
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime? Date { get; set; }
public double? Value { get; set; }
public string ValidationRule { get; set; }
public string ErrorText { get; set; }
public string InfoText { get; set; }
public string EnteredDateCache { get; set; }
public string EnteredValueCache { get; set; }
public bool Editable { get; set; }
}
}
public static class StringExtensionMethods
{
public static bool IsNumber(this String str)
{
double Number;
if (double.TryParse(str, out Number)) return true;
return false;
}
}
Looks like I was incorrectly setting the controls incorrectly in the RowDataBound event. This should be:
if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
{
var rowData = e.Row.DataItem as RowData;
if (rowData != null)
{
DataControlFieldCell txtNewDate = (DataControlFieldCell)e.Row.Cells[COL_NEW_DATE];
if (!string.IsNullOrEmpty(rowData.EnteredValueCache))
{
var txtNewValue = (e.Row.FindControl("txtNewValue") as TextBox);
txtNewValue.Enabled = txtNewDate.Enabled = (canEdit & rowData.Editable);
txtNewValue.Text = rowData.EnteredValueCache;
}
(e.Row.FindControl("lblStatus") as Label).Text = rowData.InfoText;
(e.Row.FindControl("lblError") as Label).Text = rowData.ErrorText;
}
}
Remove the following lines from SaveData:
(row.FindControl("lblStatus") as Label).Text = dataItem.InfoText;
(row.FindControl("lblError") as Label).Text = dataItem.ErrorText;
Remove the following from ValidateDataRow:
labelInfo.Text = string.Empty;
labelError.Text = string.Empty;
I am assuming that calling the following:
DataControlFieldCell txtNewValue = (DataControlFieldCell)e.Row.Cells[COL_NEW_VALUE];
if (!string.IsNullOrEmpty(rowData.EnteredValueCache))
txtNewValue.Text = rowData.EnteredValueCache;
Will remove the controls from the template column when the data is set (which would be on the invalid value as it is not cleared in the cache) which is why I saw the error when an invalid value was entered.

Dynamically dropping grid columns - effect on postbacks

I have read a number of threads here on the subject of posting back data from dynamically added datagrid columns. Everything I've read says that since the columns were added after the Init phase, they are not available in the control collection upon Postback and therefore any data posted back by these dynamically added columns is not available and cannot be restored from ViewState unless they are re-created in Page_Init. I have read that as long as the controls are re-added with identical IDS ( i.e IDS should match match posted back control ids), they will be restored from ViewState.
What if I'm not dynamically adding grid columns but rather dropping some grid columns in the code behind. So the ID's of the columns that remmin should match what was in the control collection to begin with so any data posted back should be resotored right but this is not what I'm seeing. SUppos the following is the list of columns in my ASPX page. If in my code behind I drop the "Test" column but check the checkbox in the first column. Upon postback, the checkbox selection is not maintained. I would have expected it to based on what I've read. Can someone correct my understanding on this?
<Columns>
<asp:TemplateColumn headertext="" headerstyle-width="1%" itemstyle-horizontalalign="center" FooterStyle-CssClass="DataGridFooter" FooterStyle-HorizontalAlign="Center" FooterStyle-VerticalAlign="Top">
<HeaderTemplate>
<input id="checkAll" type="checkbox" onclick="CheckAllDataGridCheckBoxes('checkboxIsSelected',this.checked)"/>
</HeaderTemplate>
<itemtemplate>
<asp:CheckBox runat="server" id="checkboxIsSelected" checked='false' />
</itemtemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Subject" HeaderStyle-Width="10%" Visible="TRUE" ItemStyle-HorizontalAlign="Center" FooterStyle-CssClass="DataGridFooter" FooterStyle-HorizontalAlign="Center" FooterStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label id="labelSubjectID" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "SubjectID") %>' />
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Test" HeaderStyle-Width="5%" Visible="TRUE" ItemStyle-HorizontalAlign="Center" FooterStyle-CssClass="DataGridFooter" FooterStyle-HorizontalAlign="Center" FooterStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label id="labelTestCode" runat="server" Text='<%# DataBinder.Eval(Container.DataItem, "TestCode") %>' />
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
Added BindGrid() and the event handler buttonApprove_click. The method SetGridColumns is the one that drops grid columns. Have included that too.
private void BindGrid()
{
try
{
SetMasterDetailControlStates(IsPageInDetailsMode());
if (!ValidateArgs())
{
gridBias.Visible = false;
return;
}
foreach (ListItem displayOption in chkboxDisplay.Items)
{
if (displayOption.Selected)
{
if (displayOption.Value == "Highlight") { _showHighlighting = true; }
}
}
/*
<Snipped>...Make procedure call to get dataset
*/
DataSet ds = sp.GetDataSet();
if (sp.RC != (int)ReturnCode.SUCCESS)
{
if ((sp.RC == (int)ReturnCode.NO_RECORDS_RETURNED))
{
labelMessage.Text = "No data found for the specified filter";
}
else if ((sp.RC == (int)ReturnCode.UNHANDLED_EXCEPTION) || (ds == null))
{
labelMessage.Text = sp.ErrorMessage;
}
ds = null;
gridBias.DataSource = ds;
EnableControls(false);
SetGridColumns();
}
else
{
gridBias.TitleText = BuildGridTitleString();
gridBias.FilterText = BuildGridFilterString();
gridBias.EnableRowsPerPageEdit = true;
SetGridColumns();
//Since grid columns are dynamically added and can change between postbacks
//make sure sort column is valid, if not unset
if (gridBias.SortColumn != null && gridBias.SortColumn.Length > 0)
{
bool foundCol = false;
foreach (DataGridColumn dg in gridBias.Columns)
{
if (gridBias.SortColumn == dg.SortExpression)
{
foundCol = true;
break;
}
}
if (!foundCol)
{
gridBias.SortColumn = "";
gridBias.SortOrder = "";
}
}
if (gridBias.SortColumn.Length == 0) gridBias.SortColumn = "TestCode";
if (gridBias.SortOrder.Length == 0) gridBias.SortOrder = "ASC";
if (gridBias.PageIndex.Length != 0 &&
!gridBias.GridViewMode.Equals(CustomDataGrid.GridViewType.SHOWALL.ToString()))
gridBias.CurrentPageIndex = Convert.ToInt32(gridBias.PageIndex);
ds.Tables[0].DefaultView.Sort = gridBias.SortColumn + " " + gridBias.SortOrder;
gridBias.DataSource = ds.Tables[0].DefaultView;
EnableControls(true);
}
gridBias.HideEmptyColumns = true;
ArrayList cols = new ArrayList();
cols.AddRange(_alRecheckColumns);
gridBias.HideEmptyColumnsList = cols;
gridBias.DataBind();
}
catch (Exception ex)
{
CodeLibrary.ErrorHandling.SetLabel("Error(" + CodeLibrary.ErrorHandling.GetMethodName() + ")", ex.Message, labelMessage, true, "ErrorMsg");
}
}
private void SetGridColumns()
{
ArrayList alCols = new ArrayList();
alCols.Add(""); //Checkbox column
alCols.Add("Subject");
ArrayList alColumnsToBeDeleted = new ArrayList();
Boolean boolColExists = false;
foreach (ListItem chart in chkboxChartType.Items)
{
if (chart.Value == "%Bias")
{
if (rblBiasOptions.SelectedValue == "Subject")
{
foreach (DataGridColumn dg in gridBias.Columns)
{
boolColExists = false;
foreach (string gridColumn in alCols)
{
if (dg.HeaderText == gridColumn)
{
boolColExists = true;
break;
}
}
if (!boolColExists)
{
alColumnsToBeDeleted.Add(gridBias.Columns.IndexOf(dg));
}
}
}
}
// Loop thru the array list and delete columns from the grid.
int count = 0;
foreach (int i in alColumnsToBeDeleted)
{
gridBias.Columns.RemoveAt(i - count); //Subtract index by columns already deleted.
count++;
}
}
protected void buttonApprove_Click(object sender, EventArgs e)
{
try
{
CheckPermission(this.ModuleId, this.GetType().BaseType.ToString(), "buttonApprove_Click");
foreach (DataGridItem i in gridBias.Items)
{
//Loop thru each row and determien values to be saved to DB
if (i.ItemType == ListItemType.Item || i.ItemType == ListItemType.AlternatingItem)
{
bool cbSelected = ((CheckBox)i.FindControl("checkboxIsSelected")).Checked;
if (cbSelected)
{
bool IsApproved = true;
string strSubjectID = ((System.Web.UI.WebControls.Label)i.FindControl("labelSubjectID")).Text;
string strTestCode = ((System.Web.UI.WebControls.Label)i.FindControl("labelTestCode")).Text;
string strSampleType = ((System.Web.UI.WebControls.Label)i.FindControl("labelSampleType")).Text;
string strTestCodeAndType = ((System.Web.UI.WebControls.Label)i.FindControl("labelTestCodeAndType")).Text;
if (((System.Web.UI.WebControls.Label)i.FindControl("labelRecheckNeedsApproval")).Text == "1")
IsApproved = true;
else
IsApproved = false;
SaveToDB(strSubjectID, strTestCode, strSampleType, strTestCodeAndType,IsApproved);
}
}
}
BindGrid();
}
catch (Exception exceptionObject)
{
string strExceptionMessage = exceptionObject.Message + "-" + exceptionObject.InnerException.Message;
CodeLibrary.ErrorHandling.SetLabel("", strExceptionMessage, labelMessage, false, "ErrorMsg"); //--- Set label text
}
}

I have a gridview control populated from a database! I want to add a button with text property "reserve" at the end of each row of the gridview.

Depending on whichh button is pressed I have to take the excursion_date_id which I will need in the next form!
SO what is best to use - buttonfield property maybe!
here is my code
First it's the Dates.class
public class Dates
{
private int excursionID;
private DateTime startdates;
private double prices;
public int ExcursionID
{
get { return excursionID; }
set { excursionID = value; }
}
public DateTime StartDates
{
get { return startdates; }
set { startdates = value; }
}
public double Prices
{
get { return prices; }
set { prices = value; }
}
public Dates()
{ }
}
}
Then I populate the gridview with the dates from my database
I want to have a button with text property "reserve" at the end of each row of the gridview!
protected void Page_Load(object sender, EventArgs e)
{
string excursionnId = Request.QueryString["ExcursionId"];
Dates date = new Dates();
List<Dates> listDate = new List<Dates>();
listDate = GetDates();
gvDates.DataSource = listDate;
gvDates.DataBind();
}
public List<Dates> GetDates()
{
List<Dates> datesList = new List<Dates>();
string connectionString = "Server=localhost\\SQLEXPRESS;Database=EXCURSIONSDATABASE;Trusted_Connection=true";
string excursionnID = Request.QueryString["ExcursionID"];
string query =
"SELECT Excursion_date_ID, Excursion_ID, Start_date, Price FROM EXCURSION_DATES WHERE EXCURSION_ID='" + excursionnID + "'";
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(query, conn);
try
{
conn.Open();
SqlDataReader rd = cmd.ExecuteReader();
int s=0;
while (rd.Read())
{
Dates dates = new Dates();
dates.ExcursionID = Convert.ToInt32(rd["Excursion_ID"]);
dates.StartDates = Convert.ToDateTime(rd["Start_date"]);
dates.Prices = Convert.ToDouble(rd["Price"]);
datesList.Add(dates);
}
}
catch (Exception EX)
{
}
return datesList;
}
}
<asp:GridView ID="gvDates" runat="server" Width="100%" AutoGenerateColumns="false"
OnRowCommand="grd_RowCommand" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btn" CausesValidation="false" CommandName="YourCommandName"
CommandArgument='<%#Eval("Excursion_ID") %>' runat="server" Text="Text" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
protected void grd_RowCommand(object sender, GridViewCommandEventArgs e)
{
string number = (string)e.CommandArgument;
if (number==null) return;
switch (e.CommandName)
{
case "YourCommandName":
Load(number);
break;
// some others command
}
}
OR without rowcommand
<asp:GridView ID="gvDates" runat="server" Width="100%" AutoGenerateColumns="false" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btn" CausesValidation="false" OnClick="btnClick"
CommandArgument='<%#Eval("Excursion_ID") %>' runat="server" Text="Text" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
protected void btnClick(object sender, EventArgs e)
{
Button btn=(Button)sender;
if(btn==null) return;
string number = (string)btn.CommandArgument;
if (number==null) return;
Load(number);
}
In your .aspx page, specify the id of the GridView button to the ExcursionID. You can use buttonfield or place a button in a template column for that.

OnCheckedChanged Nested Listview Controls

I have the following nested listview...
<asp:ListView ID="lvwRiskQuestions" runat="server" ItemPlaceholderID="QuestionItemPlaceholder">
<LayoutTemplate>
<asp:PlaceHolder ID="QuestionItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<%# Eval("DESCRIPTION")%>
<asp:ListView ID="lvwAnswers" runat="server" ItemPlaceholderID="AnswerItemPlaceholder" DataSource='<%# Eval("Answers")%>'>
<LayoutTemplate>
<asp:PlaceHolder ID="AnswerItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<asp:RadioButton ID="rdbSelect" runat="server" AutoPostBack="true" OnCheckedChanged="rdbSelectChanged"/>
<%# Eval("Description")%>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
I get hold of the radio buttons OnCheckedChanged like so...
Protected Sub rdbSelectChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Dim rb1 As RadioButton = CType(sender, RadioButton)
Dim lvwAnswers = DirectCast(lvwRiskQuestions.FindControl("lvwAnswers"), ListView)
For Each row As ListViewItem In lvwAnswers.Items
Dim rb As RadioButton = row.FindControl("rdbSelect")
If rb IsNot Nothing AndAlso rb.Checked Then
rb.Checked = False
End If
Next
rb1.Checked = True
End Sub
The problem i have is 'lvwAnswers' is Nothing. I'm guessing im not doing my findcontrol correctly.
Any help greatly appreciated.
If you're just generating a list of radio-buttons for the answers, you could use the RadioButtonList control. This would generate the correct HTML so that only one answer could be selected per question without having to post-back to de-select the other options.
If your answer template contains more than a single RadioButton, things get more complicated. When it's not hosted in a RadioButtonList, the RadioButton uses the UniqueID of the parent NamingContainer to build its unique group name. Unfortunately, in your example, the NamingContainer will be the ListViewDataItem from the lvwAnswers list, and each answer will have a different ID.
What you need is a RadioButton which will look at the NamingContainer's NamingContainer to generate its group name. You could either re-implement the RadioButton control, or use a little bit of reflection to update the private _uniqueGroupName field:
[ToolboxData("<{0}:ListRadioButton runat=\"server\" />")]
public class ListRadioButton : RadioButton
{
private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
private string _uniqueGroupName;
private static FieldInfo FindUniqueGroupNameField()
{
return typeof(RadioButton).GetField("_uniqueGroupName",
BindingFlags.NonPublic | BindingFlags.Instance);
}
protected virtual string CreateUniqueGroupName()
{
string result = GroupName;
if (string.IsNullOrEmpty(result))
{
result = ID;
}
if (string.IsNullOrEmpty(result))
{
result = UniqueID;
}
else
{
Control container = NamingContainer;
if (container != null)
{
if (container is IDataItemContainer)
{
container = container.NamingContainer ?? container;
}
result = container.UniqueID + base.IdSeparator + result;
}
else
{
string uniqueID = UniqueID;
if (!string.IsNullOrEmpty(uniqueID))
{
int index = uniqueID.LastIndexOf(base.IdSeparator);
if (index != -1)
{
result = uniqueID.Substring(0, 1 + index) + result;
}
}
}
}
return result;
}
private void EnsureUniqueGroupName()
{
if (_uniqueGroupName == null)
{
string value = CreateUniqueGroupName();
if (UniqueGroupNameField != null) UniqueGroupNameField.SetValue(this, value);
_uniqueGroupName = value;
value = base.Attributes["value"];
if (string.IsNullOrEmpty(value))
{
base.Attributes["value"] = UniqueID;
}
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
EnsureUniqueGroupName();
return base.LoadPostData(postDataKey, postCollection);
}
protected override void Render(HtmlTextWriter writer)
{
EnsureUniqueGroupName();
base.Render(writer);
}
}
With that control in place and registered using the site prefix, you can change your code to:
<asp:ListView ID="lvwRiskQuestions" runat="server" ItemPlaceholderID="QuestionItemPlaceholder">
<LayoutTemplate>
<asp:PlaceHolder ID="QuestionItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<%# Eval("DESCRIPTION") %>
<asp:ListView ID="lvwAnswers" runat="server" ItemPlaceholderID="AnswerItemPlaceholder" DataSource='<%# Eval("Answers")%>'>
<LayoutTemplate>
<asp:PlaceHolder ID="AnswerItemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<site:ListRadioButton ID="rdbSelect" runat="server"
Text='<%# Eval("Description") %>'
/>
</ItemTemplate>
</asp:ListView>
</ItemTemplate>
</asp:ListView>
In the rendered HTML, the radio-buttons for each question will then have the same name, and you will only be able to select a single answer per question, without having to post the entire page on each selection.
I'd like to point out that this "copy/paste" code doesn't work and was taken from a comment on codeproject (Comment titled Another Option). The original code does work.
Here it is :
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Reflection;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class SimpleRadioButton : RadioButton
{
private static readonly FieldInfo UniqueGroupNameField = FindUniqueGroupNameField();
private string _uniqueGroupName;
private static FieldInfo FindUniqueGroupNameField()
{
return typeof(RadioButton).GetField("_uniqueGroupName",
BindingFlags.NonPublic | BindingFlags.Instance);
}
protected virtual string CreateUniqueGroupName()
{
string result = this.GroupName;
if (string.IsNullOrEmpty(result))
{
result = this.ID;
}
if (string.IsNullOrEmpty(result))
{
result = this.UniqueID;
}
else
{
Control container = this.NamingContainer;
if (null != container)
{
if (container is IDataItemContainer)
{
container = container.NamingContainer ?? container;
}
result = container.UniqueID + base.IdSeparator + result;
}
else
{
string uniqueID = this.UniqueID;
if (!string.IsNullOrEmpty(uniqueID))
{
int index = uniqueID.LastIndexOf(base.IdSeparator);
if (-1 != index)
{
result = uniqueID.Substring(0, 1 + index) + result;
}
}
}
}
return result;
}
private void EnsureUniqueGroupName()
{
if (null == _uniqueGroupName)
{
string value = this.CreateUniqueGroupName();
if (null != UniqueGroupNameField) UniqueGroupNameField.SetValue(this, value);
_uniqueGroupName = value;
// Make sure we have a value attribute:
value = base.Attributes["value"];
if (string.IsNullOrEmpty(value))
{
base.Attributes["value"] = this.UniqueID;
}
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
this.EnsureUniqueGroupName();
return base.LoadPostData(postDataKey, postCollection);
}
protected override void Render(HtmlTextWriter writer)
{
this.EnsureUniqueGroupName();
base.Render(writer);
}
}

ASP.NET - User control custom data binding

I develop user control Date of Birth, which contains 3 DropDownList.
I need to make data binding, but I dunno how.
public partial class DofControl : System.Web.UI.UserControl {
public const int YearsCount = 100;
int _year;
Months _month;
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack ) {
Bind();
}
if (SessionWrapper.JustInserted)
{
Bind();
SessionWrapper.JustInserted = false;
}
}
public object DataSource {
get; set;
}
private void Bind() {
int[] years = new int[YearsCount];
int from = DateTime.Now.Year - 5;
int to = from - 100;
for (int i = 0; i < YearsCount; i++) {
years[i] = to;
to++;
}
ddlYear.DataSource = years;
ddlYear.DataBind();
ddlMonth.DataSource = Enum.GetNames(typeof(Months));
ddlMonth.DataBind();
_year = Int32.Parse(ddlYear.SelectedValue);
_month = (Months)Enum.Parse(typeof(Months), ddlMonth.SelectedValue);
BindDays(_year, _month);
if (DataSource==null)
{
ddlYear.SelectedValue = years.Max().ToString();
ddlMonth.SelectedValue = Months.January.ToString();
ddlDay.SelectedValue = "1";
}
else
{
ddlYear.SelectedValue = Convert.ToDateTime(DataSource).Year.ToString();
ddlMonth.SelectedValue = Enum.GetName(typeof(Months), Convert.ToDateTime(DataSource).Month);
ddlDay.SelectedValue = Convert.ToDateTime(DataSource).Day.ToString();
}
}
enum Months { January = 1 //....... }
//Is this right?
[Bindable(true,BindingDirection.TwoWay)]
public DateTime Date {
private get {
return DateTime.Parse(string.Format("{0}/{1}/{2}", ddlDay.Text, ddlMonth.Text, ddlYear.Text));
}
set
{
ddlYear.SelectedValue = value.Year.ToString();
ddlMonth.SelectedValue = value.Month.ToString();
ddlDay.SelectedValue = value.Day.ToString();
}
}
protected void ddlMonth_SelectedIndexChanged(object sender, EventArgs e) {
_year = int.Parse(ddlYear.SelectedValue);
_month = (Months)Enum.Parse(typeof(Months), ddlMonth.SelectedValue);
BindDays(_year, _month);
}
protected void ddlYear_SelectedIndexChanged(object sender, EventArgs e) {
_year = int.Parse(ddlYear.SelectedValue);
_month = (Months)Enum.Parse(typeof(Months), ddlMonth.SelectedValue);
BindDays(_year, _month);
}
public bool IsLeapYear(int year) { //..... }
private void BindDays(int year, Months month) {
List<int> days = new List<int>();
switch (month) {
case Months.January:
case Months.March:
for (int i = 1; i <= 31; i++)
days.Add(i);
break;
case Months.February:
//does not matter
}
}
I use DofControl in a page Update.aspx inside asp:DetailsView.
<asp:ObjectDataSource ID="odsOneStudent" runat="server"
SelectMethod="GetStudentById"
..////
<asp:DetailsView
//......
<Fields>
<asp:BoundField DataField="SurName" HeaderText="SurName" />
<asp:TemplateField HeaderText="Dof">
<EditItemTemplate>
<uc:Dof runat="server" ID="dfDof" Date='<%#Eval("Dof") %>' />
</EditItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
I does not work, I get an error "ddlMonth' has a SelectedValue which is invalid because it does not exist in the list of items.
Parameter name: value"
Am I miss anything?
update: I get an error: "Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control"
When you set the SelectedValue of a DropDownList the value must be contained in the list's items.
Check where you are setting the SelectedValue that the value you are using is correct and contained in the DropDownList.Items

Resources