Avoid "magic strings" in databound web controls? - asp.net

Is there a way to bind data to controls using the properties being bound to them so re-factoring and typos aren't so much of an issue?
For example, instead of assigning field names to a drop-down list like ddl.DataTextField = "FieldName"; ddl.DataValueField = "Id", I would hypothetically write ddl.DataTextField = MyClass.FieldName; ddl.DataValueField = MyClass.Id;.
Edit:
I'm thinking about having my objects implement an interface that has DataTextField and DataValueField (or similarly named) properties so, at the very least, my DDLs would be consistently bound.
This wouldn't help in the case of ListViews, GridViews, etc. though.

I am not sure if this is what you are thinking, but maybe it will help out.
private void PopulateDropDown( List<MyClass> myClassList )
{
// Loop through myClassList.
foreach ( MyClass m in myClassList )
{
// Add myClass to the drop down list.
ListItem item = new ListItem( m.FieldName, m.Id.ToString() );
ddl.Items.Add( item );
}
}

Related

ASP:ListBox Get All Values As Selected Items

I'm just wondering how can I possibly get all values in a ListBox as selectedItems? Note that the viewed records came from an SQL datasource. I'll be using these values as list of email addresses for an email blast.
Any help would be much appreciated, thanks.
I'm using ASP.Net C#
if you want to select all items in a listbox control, Use This
listView1.MultiSelect = true;
foreach (ListItem item in ListBox1.Items )
{
item.Selected = true;
}
or you can do like this with LINQ :
Just pass your listview and checkstate to the function.
public void CheckAllItems(ListView lvw, bool check)
{
lvw.Items.OfType<ListViewItem>().ToList().ForEach(item => item.Checked = check);
}

Bind multiple dropdownlists to same datasource using loop

I have a form with 15 dropdownlists inside a table. I would like populate each ddl with the same values from a single datasource.
Instead of doing the below x 15:
ddl.datasource = x
ddl.databind()
Is it possible to loop through all the DDL's in a table and assign the datasource etc all in one go?
Something like this? (I know the code is wrong but I am unsure of the full correct code)
For Each ctrl In tblNetwork.Controls
If TypeOf ctrl Is DropDownList Then
ddl.DataSource = usr
ddl.DataBind()
End If
Next ctrl
Seems a basic one but it's got me stumped.
You are getting stumped because your method is only going to traverse the top-level controls since iterating over tblNetworks.Controls won't be recursive.
I think that this is, in general, a very bad idea because your page will suffer from the recursion that you need to make in order to catch all the dropdowns in the page. With that said, here's a solution (in C#, sorry) that will work, regardless of the level of nesting of your dropdown lists.
First, you need to create a helper method that flattens any IEnumerable so we can use LINQ:
public static class ControlExtensions
{
public static IEnumerable<T> Flatten<T>( this IEnumerable<T> e, Func<T, IEnumerable<T>> f)
{
return e.SelectMany(c => f(c).Flatten(f)).Concat(e);
}
}
And now your code becomes this:
var result = this.Controls.Cast<DropDownList>().Flatten(x=>x.Controls.Cast<DropDownList>());
DropDownList current;
foreach (var item in result)
{
if (item is DropDownList)
{
current = item as DropDownList;
current.DataSource = your_data_source;
current.DataBind();
}
}
You can obviously extend this further to do the same on any page you need to, but the more complicated your page is, the bigger your performance hit.
I hope I persuaded you from doing this...

How to dynamically hide fields in a DetailsView (fields count is always 0)

I am using a DetailsView to show the details of a single row from a DataTable.
I do not know the column names at design time, so I have AutoGenerateRows = true in the markup.
DataView dv = myDataTable.AsDataView();
dv.RowFilter = string.Format("ResourceID = {0}", resourceId);
dvScoresBreakdown.DataSource = dv;
dvScoresBreakdown.DataBind();
There are about 4 columns in the DataView which I don't want the DetailsView to display - mainly ID columns.
I understand that I should access the Fields property of the DataView and set the relevant fields invisible:
dvScoresBreakdown.Fields[0].Visible = false;
dvScoresBreakdown.Fields[1].Visible = false;
However, the .Fields.Count is always zero. So I get an index out of bounds exception.
When I say "always zero", I mean it's zero right after the .DataBind(), and also in the OnDataBinding, OnDataBound, and OnPreRender events.
But, the DetailsView does render on the page and show everything - all the columns in the original DataView - so the dataview is binding!
What am I doing wrong?
I've just found out, the way to do it is to remove rows right after the .DataBind() method.
dvScoresBreakdown.DataSource = dv;
dvScoresBreakdown.DataBind();
dvScoresBreakdown.Rows[0].Visible = false;
dvScoresBreakdown.Rows[1].Visible = false;
Hope this can help someone else!
The Columns collection only stores the explicitly declared columns, so if you’re using autogenerated columns, the count will be zero.
If you’re using autogenerated column, after databind you could loop through the rows collection and make the appropriate cells invisible, like:
If dvScoresBreakdown is GridView
dvScoresBreakdown .DataBind();
if (dvScoresBreakdown .Columns.Count > 0)
dvScoresBreakdown .Columns[0].Visible = false;
else
{
dvScoresBreakdown .HeaderRow.Cells[0].Visible = false;
foreach (GridViewRow gvr in dvScoresBreakdown .Rows)
{
gvr.Cells[0].Visible = false;
}
}
I think this will help you.

How can I Browse (only) checkbox in a panel?

I have this code :
foreach (MyObject object in MyObject)
{
Literal checkBoxStart = new Literal();
Literal checkBoxEnd = new Literal();
checkBoxStart.Text = "<div class=\"item\">";
checkBoxEnd.Text = "</div>";
CheckBox chb = new CheckBox();
chb.InputAttributes.Add("value", object.UniqueID);
chb.Text = object.Title;
panelLocalita.Controls.Add(checkBoxStart);
panelLocalita.Controls.Add(chb);
panelLocalita.Controls.Add(checkBoxEnd);
}
than, on cmdSend_Click(object sender, EventArgs e) method, I'd like to browse the panel, and check only Checkboxs. How can I do it?
Assuming I understand what you mean by browse, you could do something like:
foreach (CheckBox chb in panelLocalita.Controls.OfType<CheckBox>())
{
}
You must have a using System.Linq to make this work.
You can dig into the Linq tool box. There's a few methods that work on IEnumerable and since ControlsCollection implements that interface you can use them directly on the collection. One of the methods suits your needs very nicely.
The extension method OfType<TResult>() will iterate the collection and only return those elements that is of the provided type.
to get all the checkboxes you could do as follows:
var checkboxes = panelLocalita.Controls.OfType<CheckBox>();
and you can then either iterate via a foreach if you wish for side effects such as setting all to checked
foreach(var checkBox in checkboxes)
{
checkBox.Checked = true;
}
or if you need to grab information from them you can use more tools from the Linq tool box such as if you wanted to only grab those that are checked:
checkboxes.Where(c=>c.Checked)
or to check that all are checked
checkboxes.All(c=>c.Checked)

Accessing asp.net tablerow child control by type

I'm iterating through a collection of asp:tablerows to be able to get or set the text in a textbox that is nested in the third cell of the row; I'm doing this by type rather than by ID because the cell ID's in that column aren't totally consistent--thus I can't really call FindControl() to achieve this. I've resorted to casting the third control in the TableRow to a TableCell and then Casting the first control in that cell to a TextBox. Not quite correct, as I'm getting an index out of range exception thrown. The problem mainly lies in the Controls.Count() property of the third cell, which comes to zero.
Not sure if there's a better way to access the textbox---should I resort to FindControl()?
The code:
foreach (TableRow row in tblProviders.Rows) {
string value = ((TextBox)((TableCell)row.Controls(2)).Controls(0)).Text;
...
}
My searches here only yielded use of FindControl(), so that may be the only way...
Thanks!
You could use Linq as follows:
var TextBoxes = tblProviders.Rows.OfType<TableRow>()
.SelectMany(row => row.Cells.OfType<TableCell>()
.SelectMany(cell => cell.Controls.OfType<TextBox>()));
TextBoxes would then be a collection of all the textboxes in tblProviders.Rows, which you could then itterate through and do what you like with.
A little bit of null checking wouldn't go amiss here.
You could try using this Recursive call:
foreach (TableRow row in tblProviders.Rows) {
var tb = FindControlRecursive(row, typeof(TextBox));
if (tb != null) {
string value = ((TextBox)tb).Text;
}
}
private Control FindControlRecursive(Control rootControl, Type controlType) {
if (rootControl.GetType() == controlType)
return rootControl; //Found it
foreach (Control controlToSearch in rootControl.Controls) {
Control controlToReturn = FindControlRecursive(controlToSearch, controlType);
if (controlToReturn != null) return controlToReturn;
}
return null;
}

Resources