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)
Related
i have created dynamic listboxes (4 to 10) in ASP.NET.
and my question is , How do i find the dynamically created listboxes using c#?
thanks
Sure... and i appreciate your help . below code i am using for creating dynamic LB
protected void btndyfilter_Click(object sender, EventArgs e)
{
int numberOfListBox = lbFilter.GetSelectedIndices().Length;
string lbname = lbFilter.SelectedValue;
for (int i = 0; i < numberOfListBox; i++)
{
ListBox listb = new ListBox();
ListItem lItem = new ListItem();
listb.SelectionMode = System.Web.UI.WebControls.ListSelectionMode.Multiple;
listb.Height = 150;
listb.Width = 200;
lItem.Value = i.ToString();
lItem.Text = lbname;
listb.Items.Add(lItem);
panFilter.Controls.Add(listb);
//once we created the LB dynamically i need to populate each LB with the corresponding values
connstr2 = System.Configuration.ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;
conn2.ConnectionString = connstr2;
conn2.Open();
CubeCollection CubeList = conn2.Cubes;
string cb = ddlCubeList.SelectedItem.Text;
//need to remove the Hardcoded Code
foreach (Member dimem in CubeList[cb].Dimensions["Date"].Hierarchies["Calendar Date"].Levels["Date"].GetMembers())
{
ListItem Memlist = new ListItem();
Memlist.Text = dimem.UniqueName;
lbFilter.Items.Add(Memlist);
}
}
panFilter.Visible = true;
panCubeDef.Visible = true;
}
so this will create the LB i believe :)... and Inside the commented code i need to use to populate for each LB item ..perhaps it bit hardcoded which i need to remove. so i all dynamic LBs are populated then the selected items from all LBs will come into the where clause in my MDX query..hope i did not confuse you
There is 2 way either you can store dynamic control detail with dictionary or just find when you want to use it using some code like this
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;
return null;
}
while generating ListBox dynamically, give ListBox ID as:
lstBoxNo1, lstBoxNo2. lstBoxNo3 etc. where 1,2,3(no) will be from count.
like
int count=1;
generate listbox control
listboxid=lastBoxNo+count;
count++
`by doing this, u have control over id's.
else use
http://stackoverflow.com/questions/3731007/using-findcontrol-to-find-control
using this link to understand findcontrol.
The points that you wont to find that dynamic controls are.
The moment you first render the page.
On every other post back.
In the case of 1, then you better keep a variable on your page that keep that creations.
In the case of 2, when you have post back, you need to store somehow the creations of your control in the page when you render it. One good place is to keep that information on the viewstate.
You can also on the post back, just to check if you have any post back valued from controls that you have named with a serial numbering starting from 1, eg You start looking if you have post back from ControlName_1, then ControlName_2, and when you not found any other value you end.
I've some UserControls which are created dynamically, with parameters :
foreach (DataRow dr in drc)
{
question = (from ques in bdd.QUESTION where ques.ID_QUESTION == idQuestion select ques).FirstOrDefault();
List<Object> listParams = new List<Object>();
listParams.Add(question);
AdminQuestion qa = (AdminQuestion)(Controller.LoadControl(Page, "~/UserControls/AdminQuestion.ascx", listParams.ToArray()));
pnl_question_list.Controls.Add(qa);
}
This is a method I found on SoF and it works great.
This method is called when I click on a button, and all my usercontrols are correctly created.
In this usercontrol, I have a button :
<asp:Button ID="btn_validation_modify_question" runat="server" Text="Modifier"
CssClass="clear_left_float_left myBouton myBoutonEnvoyer"
OnClick="btn_validation_modify_question_Click"/>
And my method :
protected void btn_validation_modify_question_Click(object sender, EventArgs e)
{
QUESTION q = (from m in bdd.QUESTION where m.ID_QUESTION == question.ID_QUESTION select m).FirstOrDefault();
q.MESSAGE = txt_modify_question_message.InnerText;
q.ID_THEME = new Guid(ddl_modify_question_theme.SelectedValue);
bdd.ApplyCurrentValues<QUESTION>("QUESTION", q);
bdd.SaveChanges();
}
But when I click on the button, it don't apply the method, and reload the page, like if I didn't have any declared method.
Is there something I don't know? I already used this technique and everything worked...
If you add controls dynamically, you'll normally need to do it on Init or PreInit page events. Otherwise event handlers will never work.
So, dynamically added controls must be programmatically added to the Web page on each and every page visit. The best time to add these controls is during the initialization stage of the page life cycle, which occurs before the load view state stage. That is, we want to have the control hierarchy complete before the load view state stage arrives. For this reason, it is best to create an event handler for the Page class's Init event in your code-behind class, and add your dynamic controls there.
Note You may be able to get away with loading your controls in the
Page_Load
event handler and maintaining the view state properly. It all depends on whether or not you are setting any properties of the dynamically loaded controls programmatically and, if so, when you're doing it relative to the
Controls.Add(dynamicControl)
line. A thorough discussion of this is a bit beyond the scope of this article, but the reason it may work is because the
Controls
property's
Add()
method recursively loads the parent's view state into its children, even though the load view state stage has passed.
Here you have more information.
EDIT
Just to be sure we're talking about the same, here you have how your code should look like
protected void Page_Init(object sender, EventArgs e)
{
...
foreach (DataRow dr in drc)
{
question = (from ques in bdd.QUESTION where ques.ID_QUESTION == idQuestion select ques).FirstOrDefault();
List<Object> listParams = new List<Object>();
listParams.Add(question);
AdminQuestion qa = (AdminQuestion)(Controller.LoadControl(Page, "~/UserControls/AdminQuestion.ascx", listParams.ToArray()));
pnl_question_list.Controls.Add(qa);
}
...
}
PageLoad(){
If(!Page.IsPostBack())
foreach (DataRow dr in drc)
{
question = (from ques in bdd.QUESTION where ques.ID_QUESTION == idQuestion select ques).FirstOrDefault();
List<Object> listParams = new List<Object>();
listParams.Add(question);
AdminQuestion qa = (AdminQuestion)(Controller.LoadControl(Page, "~/UserControls/AdminQuestion.ascx", listParams.ToArray()));
pnl_question_list.Controls.Add(qa);
}
}
Did you try with this solution? And not use Page_Init()?
I know this has been asked before, but I've found a different way to get references to controls in external JS files but I'm not sure how this would go down in terms of overall speed.
My code is
public static void GenerateClientIDs(Page page, params WebControl[] controls) {
StringBuilder script = new StringBuilder();
script.AppendLine("<script type=\"text/javascript\">");
foreach (WebControl c in controls) {
script.AppendLine(String.Format("var {0} = '#{1}';", c.ID, c.ClientID));
}
script.AppendLine("</script>");
if (!page.ClientScript.IsClientScriptBlockRegistered("Vars")) {
page.ClientScript.RegisterClientScriptBlock(page.GetType(), "Vars", script.ToString());
}
}
This was I can reference the id of the aspx page in my JS files.
Can anyone see any drawbacks to doing things this way? I've only started using external JS files. Before everything was written into the UserControl itself.
Well, the method can only be used once in each page, so if you are calling it from a user control that means that you can never put two of those user controls on the same page.
You could store the control references in a list until the PreRender event, then put them all in a script tag in the page head. That way you can call the method more than once, and all client IDs are put in the same script tag.
Something like:
private const string _key = "ClientIDs";
public static void GenerateClientIDs(params WebControl[] controls) {
Page page = HttpContext.Current.Handler As Page;
List<WebControl> items = HttpContext.Current.Items[_key] as List<WebControl>;
if (items == null) {
page.PreRender += RenderClientIDs;
items = new List<WebControl>();
}
items.AddRange(controls);
HttpContext.Current.Items[_key] = items;
}
private static void RenderClientIDs() {
Page page = HttpContext.Current.Handler As Page;
List<WebControl> items = HttpContext.Current.Items[_key] as List<WebControl>;
StringBuilder script = new StringBuilder();
script.AppendLine("<script type=\"text/javascript\">");
foreach (WebControl c in items) {
script.AppendLine(String.Format("var {0} = '#{1}';", c.ID, c.ClientID));
}
script.AppendLine("</script>");
page.Head.Controls.Add(new LiteralControl(script));
}
Check this out: http://weblogs.asp.net/joewrobel/archive/2008/02/19/clientid-problem-in-external-javascript-files-solved.aspx
Looks like it takes care of the dirty work for you (something like Guffa's answer). It generates a JSON object (example) containing server IDs and client IDs, so you can do something like this in your JavaScript:
var val = PageControls.txtUserName.value;
I want to bind a List to a GridView on a web page, but override the way the property names display via annotation. I thought System.ComponentModel would work, but this doesn't seem to work. Is this only meant for Windows Forms?:
using System.ComponentModel;
namespace MyWebApp
{
public class MyCustomClass
{
[DisplayName("My Column")]
public string MyFirstProperty
{
get { return "value"; }
}
public MyCustomClass() {}
}
Then on the page:
protected void Page_Load(object sender, EventArgs e)
{
IList<MyCustomClass> myCustomClasses = new List<MyCustomClass>
{
new MyCustomClass(),
new MyCustomClass()
};
TestGrid.DataSource = myCustomClasses;
TestGrid.DataBind();
}
This renders with "MyFirstProperty" as the column header rather than "My Column." Isn't this supposed to work?
When using .net 4 or later you can use gridview1.enabledynamicdata(typeof(mytype)). I haven't looked at all the types you can use there but I know the [displayname("somename")] works well but the [browsable(false)] doesn't omit the column from the grid. It looks like a knit one slip one from MS. at least you can easily rename column names and to omit a column I just declare a variable instead of using a property. It has the same effect...
Just by the way, using the designer to create columns is the easy way out but to just show a different column name takes way to much time especially with classes with many fields.
What SirDemon said...
The answer appears to be no, you can't. At least not out of the box.
The System.Web.UI.WebControls.GridView uses reflected property's name:
protected virtual AutoGeneratedField CreateAutoGeneratedColumn(AutoGeneratedFieldProperties fieldProperties)
{
AutoGeneratedField field = new AutoGeneratedField(fieldProperties.DataField);
string name = fieldProperties.Name; //the name comes from a PropertyDescriptor
((IStateManager) field).TrackViewState();
field.HeaderText = name; //<- here's reflected property name
field.SortExpression = name;
field.ReadOnly = fieldProperties.IsReadOnly;
field.DataType = fieldProperties.Type;
return field;
}
While System.Windows.Forms.DataGridView uses DisplayName if available:
public DataGridViewColumn[] GetCollectionOfBoundDataGridViewColumns()
{
...
ArrayList list = new ArrayList();
//props is a collection of PropertyDescriptors
for (int i = 0; i < this.props.Count; i++)
{
if (...)
{
DataGridViewColumn dataGridViewColumnFromType = GetDataGridViewColumnFromType(this.props[i].PropertyType);
...
dataGridViewColumnFromType.Name = this.props[i].Name;
dataGridViewColumnFromType.HeaderText = !string.IsNullOrEmpty(this.props[i].DisplayName) ? this.props[i].DisplayName : this.props[i].Name;
}
}
DataGridViewColumn[] array = new DataGridViewColumn[list.Count];
list.CopyTo(array);
return array;
}
Unfortunately, while you can override the CreateAutoGeneratedColumn, neither the missing DisplayName nor underlying property descriptor gets passed, and you can't override CreateAutoGeneratedColumns (although you could CreateColumns).
This means you'd have to iterate over reflected properties yourself and in some other place.
If all you care about is the header text in GridView, just use the HeaderText property of each field you bind. If you're autogenerating the columns, you just set the HeaderText after you've bound the GridView.
If you want a GridView that takes into account some attribute you placed on the properties of your bound class, I believe you'll need to create your own GridView.
I may be wrong, but I've not seen any ASP.NET Grid from control vendors (at least Telerik , Janus Systems and Infragistics) do that. If you do it, maybe sell the idea to them.
Are you using .net4, what you need to do is to set enabledynamicdata on the grid view to true.
You can do it now on asp.net mvc2. It works just like that
I'm modifying the "Edit.aspx" default page template used by ASP.NET Dynamic Data and adding some additional controls. I know that I can find the type of object being edited by looking at DetailsDataSource.GetTable().EntityType, but how can I see the actual object itself? Also, can I change the properties of the object and tell the data context to submit those changes?
Maybe you have found a solution already, however I'd like to share my expresience on this.
It turned out to be a great pita, but I've managed to obtain the editing row. I had to extract the DetailsDataSource WhereParameters and then create a query in runtime.
The code below works for tables with a single primary key. If you have compound keys, I guess, it will require modifications:
Parameter param = null;
foreach(object item in (DetailsDataSource.WhereParameters[0] as DynamicQueryStringParameter).GetWhereParameters(DetailsDataSource)) {
param = (Parameter)item;
break;
}
IQueryable query = DetailsDataSource.GetTable().GetQuery();
ParameterExpression lambdaArgument = Expression.Parameter(query.ElementType, "");
object paramValue = Convert.ChangeType(param.DefaultValue, param.Type);
Expression compareExpr = Expression.Equal(
Expression.Property(lambdaArgument, param.Name),
Expression.Constant(paramValue)
);
Expression lambda = Expression.Lambda(compareExpr, lambdaArgument);
Expression filteredQuery = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, query.Expression, lambda);
var WANTED = query.Provider.CreateQuery(filteredQuery).Cast<object>().FirstOrDefault<object>();
If it's a DD object you may be able to use FieldTemplateUserControl.FindFieldTemplate(controlId). Then if you need to you can cast it as an ITextControl to manipulate data.
Otherwise, try using this extension method to find the child control:
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
T found = startingControl.FindControl(id) as T;
if (found == null)
{
found = FindChildControl<T>(startingControl, id);
}
return found;
}
I found another solution, the other ones did not work.
In my case, I've copied Edit.aspx in /CustomPages/Devices/
Where Devices is the name of the table for which I want this custom behaviour.
Add this in Edit.aspx -> Page_Init()
DetailsDataSource.Selected += entityDataSource_Selected;
Add this in Edit.aspx :
protected void entityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
Device device = e.Results.Cast<Device>().First();
// you have the object/row being edited !
}
Just change Device to your own table name.