Binding sclar values in C# grid controls - asp.net

Recently I have been using both the ASP.Net GridView Control and the WinForms DataGridView to display data dynamically. In both cases I have been using various generic Lists as the datasource (List<T>). When this list in as a collection of types with properties defined, these controls have no problem binding to a named property, and in the case of the DataGridView will display the properties as headers with the values for each property as the rows.
However when I have a collection of strings or ints for example, these controls have trouble binding to the values contained in the lists. I'm creating my ASP GridView control dynamically so its not defined in the page untill it is needed so I don't think a binding expression will work here, although I'm new to binding expressions so I could be wrong:
GridView grid = new GridView();
grid.AutoGenerateColumns = false;
grid.CssClass = "summaryTable";
grid.Columns.Add(new TemplateField { HeaderText = "Error No.", ItemTemplate = new DataGridAutoNumber(grid) });
grid.Columns.Add(new BoundField { HeaderText = "Error Description", DataField="Value" });
grid.DataSource = validator.ValidationErrors;
grid.DataBind();
In the above example validator.ValidationErrors is a list of strings. In order to get the GridView to bind the string values I had to wrap them in a type I created:
public class ValueItem<T>
{
T value;
public ValueItem(T valueIn) { value = valueIn; }
public T Value { get { return value; } }
}
This type works for both GridView and DataGridView and allows me to create a List<ValueItem<T>>() of any value type so I can bind it to a Grid type control.
Now am I missing something here or do these controls just not work well with collections of value types?
Apologies for the long question!
P.S. As a side note if anyone knows how to create an autonumber column in a GridView in the code not the script, please let me know. My solution was this:
public class DataGridAutoNumber : ITemplate
{
GridView grid;
public DataGridAutoNumber(GridView gridIn) { grid = gridIn; }
#region ITemplate Members
public void InstantiateIn(Control container)
{
container.Controls.Add(new Label{ Text=(grid.Rows.Count+1).ToString()});
}
#endregion
}

you already know how to add Label to GridView.
Here is one logic to add auto numbering i.e. row number to grid
Untested code
protected void gv_DataBound(object sender, EventArgs e)
{
int pageIndex = gv.PageIndex;
int pagesize = 20;
int count = pagesize * pageIndex;
foreach (GridViewRow row in gv.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
count ++;
Label lbl = row.FindControl("lblAutoNumber") as Label;
lbl.Text = count.ToString();
}
}
}

Related

How can I populate a drop down box with all the possible SeriesChartType options?

I wish to populate a drop down box with each possible SeriesChartType so that my users may choose an appropriate chart type.
How can I iterate through the SeriesChartType collection (it's in the namespace System.Web.Ui.DataVisualization.Charting) and return each possible option so I can add it to the drop down box?
Thanks.
This worked for me in VB - I had to instantiate a new instance of the SeriesChartType which allowed me to use the [Enum].GetNames Method.
I was then able to add them to the drop down box as shown:
Dim z As New SeriesChartType
For Each charttype As String In [Enum].GetNames(z.GetType)
Dim itm As New ListItem
itm.Text = charttype
ddl_ChartType.Items.Add(itm)
Next
Thanks to everyone for your answers. mrK has a great C alternative to this VB code.
foreach (ChartType in Enum.GetValues(typeof(System.Web.UI.DataVisualization.Charting))
{
//Add an option the the dropdown menu
// Convert.ToString(ChartType) <- Text of Item
// Convert.ToInt32(ChartType) <- Value of Item
}
If this isn't what you're looking for, let me know.
You could bind data in the DataBind event handler:
public override void DataBind()
{
ddlChartType.DataSource =
Enum.GetValues(typeof(SeriesChartType))
.Cast<SeriesChartType>()
.Select(i => new ListItem(i.ToString(), i.ToString()));
ddlChartType.DataBind();
}
and then retrieve the selected value in the SelectedIndexChanged event handler like this:
protected void ddlChartType_SelectedIndexChanged(object sender, EventArgs e)
{
// holds the selected value
SeriesChartType selectedValue =
(SeriesChartType)Enum.Parse(typeof(SeriesChartType),
((DropDownList)sender).SelectedValue);
}
Here's a generic function:
// ---- EnumToListBox ------------------------------------
//
// Fills List controls (ListBox, DropDownList) with the text
// and value of enums
//
// Usage: EnumToListBox(typeof(MyEnum), ListBox1);
static public void EnumToListBox(Type EnumType, ListControl TheListBox)
{
Array Values = System.Enum.GetValues(EnumType);
foreach (int Value in Values)
{
string Display = Enum.GetName(EnumType, Value);
ListItem Item = new ListItem(Display, Value.ToString());
TheListBox.Items.Add(Item);
}
}

ASP.Net Custom Control

I am developing a custom control that needs to display a dropdownlist as a composite control.
The drop down list gets populated from a Rest web service. The problem I am facing is that the dropdownlist only has DataTextField and DataValueField but I need a way of storing more values in the control i.e. I have a couple of other properties I need to access for the selected item.
What is the best way of going about this?
Here is the code I have so far:
[ValidationProperty("SelectedValue")]
public class SelectSurveyControl : Panel
{
private DropDownList ddlSurveys;
public string SelectedSurveyId
{
get
{
return SelectedValue;
}
}
public string SelectedSurveyJavascriptEmbedCode
{
get
{
return this.ddlSurveys.SelectedItem.Attributes[""];
}
}
public string SelectedValue
{
get
{
return ddlSurveys.SelectedValue;
}
set
{
if (ddlSurveys == null)
{
ddlSurveys = new DropDownList();
}
ddlSurveys.SelectedValue = value;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnInit(e);
if (ddlSurveys == null)
{
ddlSurveys = new DropDownList();
}
IList<Survey> surveys = GetSurveys();
this.ddlSurveys.DataSource = surveys;
this.ddlSurveys.DataTextField = "title";
this.ddlSurveys.DataValueField = "id";
this.ddlSurveys.DataBind();
ddlSurveys.SelectedValue = this.SelectedValue;
ddlSurveys.CssClass = "umbEditorTextFieldMultiple charlimit";
ddlSurveys.Attributes.Add("SurveyId", SelectedSurveyId);
ddlSurveys.Attributes.Add("JavascriptEmbedingCode", SelectedSurveyId);
this.Controls.Add(ddlSurveys);
}
public IList<Survey> GetSurveys()
{
...
}
}
Try using a string join/split to store and retrieve the various values, then you don't have to customize your dropdown list very much.
For Example:
Text: Some Title
Value: 1|testing test|2/12/2010
This will let you store as many values as you want, so long as you choose an appropriate character to join and split on. I usually use the bar, as in my example above.
Side Note: I was looking at your selected value set handler and it needs some tweaking. You shouldn't check for a null drop down list, instead you should call EnsureChildControls() before each get and set instead. Make sure you override the CreateChildControls() method and create your controls there.
You could use a hidden field and iterate thru a copy of the returned Surveys like this:
foreach(Survey s in Surveys){
string val = s.id + ":" + s.<property1> + ":" + s.<property2>;
hiddenField.Value += val +",";
}
When you need to read from the hidden field, you use String.Split to separate the values into arrays using ',' as the separator and in each array, you split again using ':'.
In the first split Array1[0] who be the survey id and Array1[n!=0] would be the properties of the Survey with the id = Array1[0]. Array[n!=0] would then be split into Array2.
I would suggest handling empty property values with an empty string or something or else you might end up with unequal lengths especially if you specify StringSplitOptions.RemoveEmptyEntries.
Agricfowl

if i have different asp.net checkboxes in webform with different text as 450, 550, 500, 900

I have different checkboxes in vb.net webform with different text ...
checkbox1.text=100
checkbox2.text=300
checkbox3.text=550 and so on .....
i want when i check checkbox1 and checkbox2 then in textbox1 the text would be 400
means as many as checkbox i select the sun of checkboxes selected will be calculated in textbox using VB.NET ....
i m using Visual Studio 2008
If you are looking at server side code then following code should do the trick:
private int mTotal;
private void EnumerateCheckBoxes(Control control)
{
if (control is CheckBox)
{
var check = (CheckBox)control;
if (check.Checked)
{
int value;
if (int.TryParse(check.Text, out value))
{
mTotal += value;
}
}
}
else if (control.HasControls())
{
foreach(var c in control.Controls)
{
EnumerateCheckBoxes(c);
}
}
}
protected void Page_Load(Object sender, EventArgs e)
{
mTotal = 0;
EnumerateCheckBoxes(this.Form);
textbox1.Text = mTotal.ToString();
}
Although, this is in C#, it should be easy to port to VB.NET. Also few other things to consider:
This code will count radio buttons
as well as because it gets inherited
from CheckBox. If that is to be
avoided then replace if (control is
CheckBox) with if
(control.GetType() ==
typeof(CheckBox))
If you wish to consider checkboxes
from CheckBoxList then you have to
write another condition to see if
control is CheckBoxList and then
within condition, enumerate items
withing checkboxlist. Items count to
be added to total count while
selected items to be added to
checked count.
Use a hidden field and a bit of javascript to set the value, bind this event when a checkbox is checked
function UpdateValue(){
var total= 0;
$('input:checkbox:checked').each(function (i) {
val = total+ int.parse(this.value); //or html
});
$('#hiddenValField').html(total) ;
}

Have to select gridview row twice for dropdown to select correctly

I'm using the code below to extract data from a gridview and populate it into textboxes for the days and two drop downs for Project and Category.
For some rows in the gridview everything but the category ddl populates correctly. If I click the row a second time the category ddl displays the correct category.
Can anyone tell me why I have to click twice for some rows? And how do I fix this?
Thank you
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
//// Get the currently selected row using the SelectedRow property.
GridViewRow row = GridView1.SelectedRow;
txtSunday.Text = (row.Cells[6].Controls[0] as DataBoundLiteralControl).Text.Trim();
txtMonday.Text = (row.Cells[7].Controls[0] as DataBoundLiteralControl).Text.Trim();
txtTuesday.Text = (row.Cells[8].Controls[0] as DataBoundLiteralControl).Text.Trim();
txtWednesday.Text = (row.Cells[9].Controls[0] as DataBoundLiteralControl).Text.Trim();
txtThursday.Text = (row.Cells[10].Controls[0] as DataBoundLiteralControl).Text.Trim();
txtFriday.Text = (row.Cells[11].Controls[0] as DataBoundLiteralControl).Text.Trim();
txtSaturday.Text = (row.Cells[12].Controls[0] as DataBoundLiteralControl).Text.Trim();
// Set ProjectList ddl to Project in selected row
if (ProjectList.Items.FindByText(row.Cells[2].Text.Trim()) != null)
{
ProjectList.ClearSelection();
ProjectList.Items.FindByText(row.Cells[2].Text.Trim()).Selected = true;
}
/// This is the ddl that doesn't always populate correctly unless you click the
/// gridview row selector twice
// Set CategoryList ddl to Category in selected row
if (CategoryList.Items.FindByText(row.Cells[4].Text.Trim()) != null)
{
CategoryList.ClearSelection();
CategoryList.Items.FindByText(row.Cells[4].Text.Trim()).Selected = true;
}
}
I'm not sure why it's taking two clicks to get your drop down list to select correctly, but it might have to do with postback event ordering/ViewState issues. One thing you may want to consider is using the data you're binding the grid to rather than the text of the controls in the grid. IOW, assuming you're binding to an collection of objects like this:
public class ProjectSchedule
{
public string Project {get;set;}
public int CategoryId {get;set;}
public string Category {get;set;}
public string Sunday {get;set;}
public string Monday {get;set;}
public string Tuesday {get;set;}
public string Wednesday {get;set;}
public string Thursday {get;set;}
public string Friday {get;set;}
public string Saturday {get;set;}
}
Then, in the SelectedIndexChanged event handler, get your data like this:
GridViewRow row = GridView1.SelectedRow;
ProjectSchedule ps = row.DataItem as ProjectSchedule;
if (ps != null)
{
txtSunday.Text = ps.Sunday;
// the rest of the days...
ListItem categoryItem = CategoryList.Items.FindByText(ps.Category);
if (categoryItem != null)
{
CategoryList.ClearSelection();
categoryItem.Selected = true;
}
// same with ProjectList
}
Assuming your controls are going to land in the same column every time limits maintainability. For instance, say the requirements change to say the columns with the days are before the Project column. That's a lot of indices to change.
It would be even better if you have your categories and whatnot indexed by something (e.g., the CategoryId property I smuggled into the ProjectSchedule object above), then you could look up the item by value instead of by text, relieving another point of failure.
I think I figured this out. I needed to rebind the category ddl after setting the project
// Set ProjectList ddl to Project in selected row
if (ProjectList.Items.FindByText(row.Cells[2].Text.Trim()) != null)
{
ProjectList.ClearSelection();
ProjectList.Items.FindByText(row.Cells[2].Text.Trim()).Selected = true;
}
// Set CategoryList ddl to Category in selected row
// I added this line and it seems to work now
CategoryList.DataBind();
if (CategoryList.Items.FindByText(row.Cells[4].Text.Trim()) != null)
{
CategoryList.ClearSelection();
CategoryList.Items.FindByText(row.Cells[4].Text.Trim()).Selected = true;
}

Return ASP DDL or Telerik control

I'm trying to write a more generic method that will populate either an ASP.NET dropdownlist OR a telerik RadComboBox with states. I'd like to pass the control in as a parameter to the method. I have a DataTable that holds all the states, which I loop through (see below) - I'd like to make this applicable to a Telerik RadComboBox - so I need to change the first parameter, and also the part where I Insert a new ListItem - for Telerik RadComboBox it is new RadComboBoxItem. How can I do this?
public void PopulateStates(DropDownList ddlStates, string country)
{
ddlStates.Items.Clear();
DataLookup dl = new DataLookup();
DataTable dt = dl.GetStatesByCountry(country);
if (dt != null)
{
if (dt.Rows.Count > 0)
{
ddlStates.Items.Insert(0, new ListItem(""));
for (int i = 0; i < dt.Rows.Count; i++)
{
ddlStates.Items.Add(new ListItem(dt.Rows[i]["STCD_Descr"].ToString(),
dt.Rows[i]["STCD_State_CD"].ToString()));
}
}
}
}
I looked up the telerik documentation & there doesn't seem to be common way of doing - what you are trying to do.
If it is possible, try using the databinding (setting the DataSource & calling DataBind).
Note: I haven't tried it. But I think that should be supported by both.
Since ListBox and RadComboBox does not have common classes except for the "Control" class you will need to check the actual type.
How about the following code?
public void PopulateStates(Control ddl, string country)
{
object listItem = new object();
switch (ddl.GetType().Name)
{
case "RadComboBox":
listItem = listItem as RadComboBoxItem;
ddl = ddl as RadComboBox;
break;
case "ListBox":
listItem = listItem as ListItem;
ddl = ddl as ListBox;
break;
default:
return;
}
// proceed with your code
}

Resources