Return ASP DDL or Telerik control - asp.net

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
}

Related

ASP.NET: Custom CheckBoxList control losing checked state on postback

I extended the ASP.NET CheckBoxList web control to create a Bootstrap 5 layout version.
The control works fine, but on postback, it loses the checked state. Also, the control's SelectedItem property is null.
I created the same control for the RadioButtonList and it works perfectly. Using DotPeek, I see that both of those inherit the same controls and interfaces, so I can't figure out why the custom RadioButtonList maintains state but the CheckboxList doesn't.
Any ideas? The internet has no useable examples to speak of.
C#
public class Bootstrap5CheckBoxList : CheckBoxList {
protected override void Render(HtmlTextWriter writer) {
try {
var selected = false;
//var webControl = new WebControl(HtmlTextWriterTag.Div);
//webControl.ID = ClientID;
//webControl.RenderBeginTag(writer);
for (int index = 0; index < Items.Count; index++) {
var item = this.Items[index];
//div
writer.Indent++;
writer.WriteBeginTag($"div class='form-check {base.CssClass}'");
writer.Write('>');
writer.WriteLine();
//input
writer.Indent++;
writer.WriteBeginTag("input");
writer.WriteAttribute("id", $"{this.ID}_{index}");
writer.WriteAttribute("type", "checkbox");
writer.WriteAttribute("name", $"{this.UniqueID}_{index}");
var cssClass = "";
if (item.Attributes["class"] != null) {
cssClass = item.Attributes["class"];
}
writer.WriteAttribute("class", $"form-check-input {cssClass}");
writer.WriteAttribute("value", item.Value);
var clientID = this.ClientID;
if (item.Selected) {
if (selected) {
this.VerifyMultiSelect();
}
selected = true;
writer.WriteAttribute("checked", "checked");
}
if (item.Attributes.Count > 0) {
foreach (string key in item.Attributes.Keys) {
if (!"class".Equals(key)) {
writer.WriteAttribute(key, item.Attributes[key]);
}
}
}
if (!item.Enabled)
writer.WriteAttribute("disabled", "disabled");
if (this.Page != null) {
this.Page.ClientScript.RegisterForEventValidation(
this.UniqueID,
item.Value);
}
writer.Write('>');
writer.WriteEndTag("input");
writer.WriteLine();
//label
writer.WriteBeginTag("label");
writer.WriteAttribute("class", "form-check-label");
writer.WriteAttribute("for", $"{this.ID}_{index}");
writer.Write('>');
HttpUtility.HtmlEncode(item.Text, writer);
writer.WriteEndTag("label");
writer.Indent--;
writer.WriteLine();
//Close Div
writer.WriteEndTag("div");
writer.WriteLine();
writer.Indent--;
}
//webControl.RenderEndTag(writer);
} catch (Exception ex) {
throw new Exception(string.Format("{0}.{1}:{2} {3}", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.FullName, System.Reflection.MethodBase.GetCurrentMethod().Name, ex.Message, ex.StackTrace));
}
}
}
HTML
<%# Register TagPrefix="BSControls" Namespace="My.App.classes.custom_controls" Assembly="My.App" %>
<BSControls:Bootstrap5CheckBoxList ID="customCheckList" runat="server">
<asp:ListItem Value="1">Check 1</asp:ListItem>
<asp:ListItem Value="2">Check 2</asp:ListItem>
</BSControls:Bootstrap5CheckBoxList>
looks like you now using html controls, and they don't have automatic viewstate. you would be MUCH better to use a CheckBox list, and format that with bootstrap. And it also FAR better to include that checkbox list in the user control markup, and not write code to inject such controls if possible.
So, plain jane check box (input type = checkbox) as a general rule does not have automatic view state like asp.net controls. So, either drop in a check box list into your user control markup, or you may well have to add code to save/restore the values, since it looks much like you are injecting the "input" control as opposed to using a asp.net checkbox list.
After many trials, I was able to get this working and the answer is surprisingly, or maybe not, simple.
The 'name' attribute is the key and must be in the correct format.
Incorrect Format
writer.WriteAttribute("name", $"{this.UniqueID}_{index}");
Correct Format
writer.WriteAttribute("name", $"{this.UniqueID}${index}");
You must use the $ separator and not an underscore. On postback, the LoadPostData method in CheckBoxList iterates through a collection to retrieve the check state.

Validate AutoCompleteExtender

Hi
i need to validate a textbox value in order to accept only values that are in the completion list of the associated autocompleteextender control.
I'm using ajaxtoolkit (version 20229) on asp.net 2.0.
For now i use the code below to validate the textbox ; as you can see i had a hiddenfield that keep the selected key. The hiddenfield is set to 0 if the user enter a value without selecting it from the list.
Do you have any idea?
Thanks
/**** Javascript code
function AutoCompleteItemPopulated(source, eventArgs)
{
var assocHiddenField = document.getElementById( source.get_element().id+'_hidden');
assocHiddenField.value=0;
}
function AutoCompleteItemSelected(source, eventArgs)
{
var assocHiddenField = document.getElementById( source.get_element().id+'_hidden');
assocHiddenField.value = eventArgs.get_value();
}
/*****CODEBEHIND code used to populate the autocompletion list
[System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
public static string[] getStrada(string prefixText, int count, string contextKey)
{
System.Collections.Generic.List<string> items = new System.Collections.Generic.List<string>();
DataSetIncidentiTableAdapters.StradarioTableAdapter adapter = new DataSetIncidentiTableAdapters.StradarioTableAdapter();
DataSetIncidenti.StradarioDataTable dtStrade = adapter.GetStrade(contextKey, prefixText);
foreach (DataSetIncidenti.StradarioRow strada in dtStrade.Rows)
{
items.Add(AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(strada.DenominazioneCompletaVia, strada.IdStrada.ToString()));
}
return items.ToArray();
}
Yes this can be validated; you need to use a CustomValidator to do this, which you can setup both a client and server validation function, and then check the hidden field for its value.
This works great for us.
HTH.

Dynamic Template Controls

On !PostBack dynamic templates are created based on the number of rows needed for check boxes. The control id's are chkbox_id. I am unable to retrieve the dynamic check boxes via the following code and NullReferenceException is always thrown.
The code before loops through the gridview rows, then datatable dt references the possible number of dynamic columns.
for (int i = 0; i < dt.Rows.Count; i++)
{
string id = dt.Rows[i]["id"].ToString();
CheckBox cb = (CheckBox)row.FindControl("ckbox_" + id);
if (cb.Checked)
{ // do things }
}
Checkboxes defined here within page load:
if (!Page.IsPostBack)
{
foreach (DataRow dRow in dt.Rows)
{
TemplateField ckhColumn = new TemplateField();
ckhColumn.HeaderTemplate = new GridViewTemplate(ListItemType.Header, dRow["name"].ToString());
ckhColumn.ItemTemplate = new GridViewTemplate(ListItemType.Item, "ckbox_" + dRow["id"].ToString());
gvProductPriceList.Columns.Add(ckhColumn);
}
}
Let me know if I need to clarify anything else.
I'm not positive on this, and I don't have a minute to try it, but it might work if you do a row.Parent.FindControl(...). Also, if you use the as operator instead of a direct cast, you won't have the null reference exception (i.e. you can check for it):
CheckBox cb = row.Parent.FindControl("ckbox_" + id) as CheckBox;
if (cb != null)
{
// ...
}

Binding sclar values in C# grid controls

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();
}
}
}

Is there an ASP.NET collection for selected items in ListBox?

On my Asp.NET website, I have a listbox that allows multiple selections. I'd like to be able to ask something like:
blah = myListbox.selectedItems;
and be given a collection of the items that were selected in the listbox. It looks like there is a method for this in the Windows Forms world, but not for asp.NET. Is there a simpler way to do this than just iterating over the Items collection looking for selected values?
Something like this should get you the selected items:
List<ListItem> selectedItems = new List<ListItem>();
int[] selectedItemsIndexes = myListbox.GetSelectedIndices();
foreach (int selectedItem in selectedItemsIndexes)
{
selectedItems.Add(myListbox.Items[selectedItem]);
}
As an extension method:
public static class ListBoxExtensions
{
public static List<ListItem> GetSelectedItems(this ListBox listbox)
{
List<ListItem> selectedItems = new List<ListItem>();
int[] selectedItemsIndexes = listbox.GetSelectedIndices();
foreach (int selectedItem in selectedItemsIndexes)
{
selectedItems.Add(listbox.Items[selectedItem]);
}
return selectedItems;
}
}
so now you can just call:
List<ListItem> selectedItems = myListBox.GetSelectedItems();
As olle suggested the Extension method could be Linq-ified and thu shrunk down even further to:
public static class ListBoxExtensions
{
public static IEnumerable<ListItem> GetSelectedItems(this ListBox listbox)
{
var selectedItems = from ListItem i in myListbox.Items where i.Selected select i
return selectedItems;
}
}
Doesn't look like you can get the items directly, but GetSelectedIndices might help.
There is no such property but an easy linq query gets you the results fast and easy.
var selectedItems = from ListItem i in myListbox.Items where i.Selected select i;
With an extension method you can make it even simpler if you need to do this kind of thing allot.
Last time I checked, no but this may be helpful
http://tlaughlin.pandorasystems.com/blogs/tlaughlin/archive/2007/08/03/asp-net-listbox-missing-selecteditems-property.aspx

Resources