difference between dropdownlist and usercontrol with a dropdownlist - c#

i like to get initial value to my DDL and write ddl1.Text="6" - it works fine..
i try to do the same to a DDL which is part of a simple usercontrol(3 DDLs which create a date) - this doesn't work!!!
in default.aspx i tried-
DateUserControl2.SetD("17");
DateUserControl2.SetM("7");
((DropDownList)DateUserControl2.Controls[4]).Text = "2003";
in DateUserControl.ascx.cs
i put all the listitems created in Page_Init and it works fine
the other methods
public void SetD(object d)
{
this.DropDownListDuc.Text = d + "";
}
public void SetM(object m)
{
this.DropDownListMuc.SelectedValue = m + "";
}
when i try to trace, i see that the methods are ok, but, for example,if d parameter is 4 and
this.DropDownListDuc.Text = 4 + "";
is performed, still NOTHING changes!!!
(again, the same line in a "simple" DDL,like DropDownList1.Text = "20"; changes the DDL to 20!!
changing a Label in the eser control works too. it is just a DDL_in_a_usercontrol problem
thanks!

Well, keep in mind that you are NOT allowed to have two controls with the same "id" on one page.
But, what then occurs if you drop the user control two times on the same web page?
I have a hotel edit UC.
So, I can do this:
Say this markup:
<uc1:UHotelEdit runat="server" ID="UHotelEdit"
MyTable ="tblHotelsA" />
<div style="clear:both;height:30px">
</div>
<uc1:UHotelEdit runat="server" ID="UHotelEdit2"
MyTable ="tblHotelsA" />
So, note we have TWO UC's on the page. UhotelEdit, and UhotelEdit2.
My page load code is this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
UHotelEdit.MyPk = 6;
UHotelEdit.LoadData();
UHotelEdit2.MyPk = 7;
UHotelEdit2.LoadData();
}
}
And now we have this:
So, in above, we have Hotel Name text box, first name, last name etc.
But, we are NOT allowed to have multiple "id" of the same control on the page.
So, how can/could I set the hotel name of the first control to Zoo, and Zoo2 for the 2nd one?
Well, all of the controls are "nested" inside of the UC.
This is quite much like a grid view, or whatever. So, you have two choices:
if several of the controls had to be "often" changed, then make a public property in the UC.
or, you can get/grab/pluck out the control name of the UC.
eg this:
protected void Button1_Click(object sender, EventArgs e)
{
TextBox txtHotel = UHotelEdit.FindControl("txtHotel") as TextBox;
TextBox txtHotel2 = UHotelEdit2.FindControl("txtHotel") as TextBox;
txtHotel.Text = "Zoo";
txtHotel2.Text = "Zoo2";
}
And thus we now have this:
But, if you had to "often" change the hotel name text box above?
Well, then add a public property to the UC, say like this:
public string HotelName
{
get { return txtHotel.Text; }
set { txtHotel.Text = value; }
}
And now our code becomes this:
protected void Button1_Click(object sender, EventArgs e)
{
UHotelEdit.HotelName = "Zoo";
UHotelEdit2.HotelName = "Zoo2";
}
So, for common or often controls to be changed? Setup a get/set for that control. For the rare and not common used?
Then you can use find control. Quite much you do the same to get a control out of repeater, listview, gridview etc. - you in general have to use find control for those nested controls.
Well, everything quite much works the same, but we have to prefix the control(s) with the name of the user control (id) we used when dropping on the page.
but, if you have JavaScript code, then how can I select the first one (hotel name) vs the 2nd one?
Turns out, all controls rendering inside of a UC will PREFIX the control with the name of the user control!!!
So, on the page you find two hotel text boxes,
UHotelEdit_txtHotel
UhotelEdit2_txtHotel
But, they are not exposed that way to code behind (just like controls nested in a listview or repeater also are not). but, they exist and jQuery selectors can be used against those controls.
In code behind, you have to use UC.findcontrol("txtHotel") to pluck out a reference to that control in the UC - since its nested inside.
So, if your UC has a dropdown list, and you want to with ease to change that value? Then add a PUBLIC method to the control that allows you do to this. So, while the controls inside are not exposed, you can with ease add a simple public method that allows you to change the drop down list value.

Related

Is there a way to dynamically generate code to interact with buttons in C#?

I'm trying to find a a way to be able to essentially dynamically generate code based on an input.
For example I could type something like:
int Number = 22;
Button<Number>.Text = "X";
So in this case it would set button22 to have its text be an "X".
And I could change it so that I could input, for example 24 into the program and it would then set button24 to be an "X", instead of setting up a bunch of if statements to cover every potential button press.
For further context I have a Grid of 64 buttons and I need to be able to edit them individually to show to the user which buttons have been pressed, it is possible to do it with a lot of if statements but I thought it might be worth trying to find a more elegant solution.
You could have a list of buttons:
private List<Button> _buttons = new List<Button>();
Populate it like this:
for (int i = 0; i < 10; i++)
{
var b = new Button();
b.Text = $"Button #{i}";
b.Click += HandleButtonClick;
}
And you could even set an event handler on one of its events which doesn't even need to use the list (the sender is the source of the event):
private void HandleButtonClick(object sender, EventArgs e)
{
(sender as Button).Text = "X";
}
Buttons have a Tag property that can be used to hold arbitrary data about a button, this is described for WinForms, WPF and UWP.
Simple usage that is similar to OP's requirement is demonstrated in this SO post
This situation is in a practical sense the very reason that .Tag exists at all in user interface controls pretty much from the birth of c#.
So you do not need to use a custom class for a button, just simply assign your value to the .Tag property on the Button class that you are creating programmatically:
in this example a list is used to create the buttons and separate the creation from the layout, it is not necessary to do this, but may be useful. Instead, you could assign this button to it's parent container and/or set the layout margins or coordinates without keeping a reference to the Button object at all.
If OP updates the post to include implementation examples, we can update this response with more specific and complete code.
private List<Button> _buttons = new List<Button>();
// ... iteration or switching logic
var nextButton = new Button
{
Text = "x",
Tag = 22
};
nextButton.Click += DynamicButton_Click;
_buttons.Add(nextButton);
// ... later push the buttons into the parent container or bind to the UI
Then the button click handler you can access this Tag property:
this is presented from WinForms, the only difference in UWP or WPF is the method signature, change EventArgs to RoutedEventArgs
private void DynamicButton_Click(object sender, EventArgs e)
{
if(int.TryParse((sender as Button).Tag?.ToString(), out int buttonValue))
{
// use buttonValue
Console.Out.WriteLine(buttonValue);
}
else
{
// Otherwise, sender was not a button, or the button did not have an integer tag value
// either way, handle that error state here...
}
}
Using these concepts, once the buttons are created, let's say in some simple grid alignment, you could allow the user to set this Tag value at runtime if you have a TextBox (or other) input field that can be accessed from the code.
I recommend that you use MVVM style bindings for this rather than directly referencing a TextBox control, but this is simply to demonstrate the point.
private void DynamicButton_Click(object sender, EventArgs e)
{
// assign the string value from the ButtonValueTextbox control to this button
string value = this.ButtonValueTextBox.Text;
if(sender is Button button)
{
button.Tag = value;
}
else
{
// Otherwise, sender was not a button
// handle the error state here if you need to...
}
}
Now that each button has a tag, you could easily add logic to maintain unique tag values by iterating through the other buttons and clearing the tag if it was previously assigned to a different button.
Maybe you could keep a List of Button References:
var myButtons = new List<Button>();
myButtons.Add(firstButton);
myButtons.Add(secondButton);
// ... etc
// ... then somewhere else
int number = 3;
myButtons[number].Text = "xxx";

Getting subcontrol in Repeater

I am using ASP.NET and C# on .NET 4 to develop a simple app. I have a repeater with an item template containing a few controls; one of them is a label that must be set depending on a complex calculation. I am using the OnItemDataBound event to compute the text and set the label's text in the code behind, like this:
protected void repRunResults_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
//capture current context.
Repeater repRunResults = (Repeater)sender;
Label laMessage = (Label)repRunResults.Controls[0].FindControl("laMessage");
DSScatterData.RunResultsRow rRunResults = (DSScatterData.RunResultsRow)((DataRowView)(e.Item.DataItem)).Row;
//show message if needed.
int iTotal = this.GetTotal(m_eStatus, rRunResults.MaxIterations, rRunResults.TargetLimit);
if(iTotal == 100)
{
laMessage.Text = "The computed total is 100.";
}
else
{
laMessage.Text = "The computed total is NOT 100.";
}
}
The data source for my repeater contains a few rows, so I would expect that each impression of the repeater would call the event handler and show the message according to the data in the associated row. However, I only get one message, which appears on the first repeater impression but matches the data for the last row in the data source.
It seems like every time the ItemDataBound event fires, the controls that my code captures are the same ones, so that I overwrite the message on every impression of the repeater. I have stepped through the code and this is what it is apparently happening.
Any idea why? And how to fix it?
Note. My repeater is nested inside another repeater. I don't think this should be relevant, but it might be.
You are grabbing the first one. You need to use the item that is being passed in like so:
protected void repRunResults_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
//capture current context.
Repeater repRunResults = (Repeater)sender;
Label laMessage = e.Item.FindControl("laMessage"); //<-- Used e.Item here
DSScatterData.RunResultsRow rRunResults = (DSScatterData.RunResultsRow)((DataRowView)(e.Item.DataItem)).Row;
//show message if needed.
int iTotal = this.GetTotal(m_eStatus, rRunResults.MaxIterations, rRunResults.TargetLimit);
if(iTotal == 100)
{
laMessage.Text = "The computed total is 100.";
}
else
{
laMessage.Text = "The computed total is NOT 100.";
}
}

Why is my Linkbuttons command function not getting trigged?

I have this code in my codebehind:
for (int i = 0; i < linkList.Count; i++)
{
var link = UppercaseFirst(linkList[i]);
var linkButton = new LinkButton
{
Text = link + " > ",
ID = Convert.ToString(i),
CommandArgument = urlList[i]
};
linkButton.Command += new CommandEventHandler(lnkWeb_Click);
bcHolder.Controls.Add(linkButton);
}
and here is the lnkWeb_Click method:
protected void lnkWeb_Click(object sender, CommandEventArgs e)
{
var url = e.CommandArgument.ToString();
//code...
}
This method is not getting triggered when I click on one of those generated linkbuttons.
Anyone have any idea what the problem is?
Tried OnCommand="lnkWeb_Click" in the aspx file and the method got trigged, but not those that I generate by code. They dont even have OnCommand="lnkWeb_Click" attribute.
The problem here is with the control life cycle. If you want to handle events of some control properly - you have to add this control to the page on every page loading process, that is on every postback.
Look what happens in your case:
Initial button is clicked
During the post back your dynamic link buttons are added to the page, event handlers are assigned to them
User clicks on the newly generated link button
During post back these dynamic link buttons are not added to the page again, ASP.NET does not know the origin of a event so it does not call the handler.
To fix this you might need to store in the View State information about link buttons that have to be added (please do not store the controls themselves, that would be a huge overhead). Also pay attention to their IDs - they have to be the same for the same controls.
Update. Some more hints on the View State solution.
Basically you need some indicator that during the page loading you need to create some dynamic link buttons. The very basic way to do it is to store the list of the link button identifiers (or texts, or both) and then during Page_Load check if there is anything stored in View State. For example:
// Property to access the view state data
protected List<string> Links
{
get { return ViewState['links']; }
set { ViewState['links'] = value; }
}
...
protected void Page_Load(object sender, EventArgs e)
{
...
if (this.Links != null && this.Links.Count > 0)
{
// inside this method you create your link buttons and add them to the page
// you actually have this code already
RenderLinkButtons();
}
}
...
// Not sure about what name you have here
protected void InitialButtonHandlerName(object sender, EventArgs e)
{
List<string> linkList = ...; //your variable, guessing a type
// this is exactly the method you use already to add links to the page
// just one more action added to it - store info about these links into View State to use it on later post backs
this.Links = linkList;
RenderLinkButtons();
}
Please use it just a point in right direction - you might have different implementation depending on your requirements and preferences. But I hope concept is clear now.

Pass dynamically created checkboxes in ASP.NET C# across multiple Postbacks

I am stuck with a problem which I have reduced to code below . I have two buttons on an aspx page.
Both the buttons have runat="server" property and are inside <form runat="server" > tag
btnGetData
protected void btnGetData_Click(object sender, EventArgs e)
{
headlines = masg.Split('*');
//Response.Write(headlines.Length);
cb = new CheckBox[headlines.Length];
for (int i = 0; i < headlines.Length; i++)
{
cb[i] = new CheckBox();
cb[i].Text = headlines[i];
Literal br = new Literal();
br.Text = "<br/>";
Form.Controls.Add(cb[i]);
Form.Controls.Add(br);
}
}
On clicking Get Data button , multiple checkboxes are generated with associated text .
I click on some of the checkboxes and then click on Show button which IF WORKS CORRECTLY should combine selected checboxes text into single string and display it.
btnShow
protected void btnShow_Click(object sender, EventArgs e)
{
for (int i = 0; i < headlines.Length; i++)
{
if (cb[i].Checked)
newmsg += cb[i].Text + '*';
}
Response.Write("<BR><BR><BR>" + newmsg);
}
But once I click on GetData button , the checkboxes are lost as they don't persist . I read about SESSION variables but can't figure out how to apply them .
I have declared below variables as global so that they can be accessed throughout the page.
CheckBox[] cb;
string[] headlines;
string masg;
Please help with code .Please provide me with inputs in code. I will refine my question if I am not able to make something clear.
You need to recreate dynamically created controls on every postback(in Page_Init or Page_Load) due to the statelessness of HTTP. You need to know what you have to recreate. Therefore you can save the number of already created CheckBoxes in a ViewState variable.
You only need to assign the same IDs as before and add them in Page_Load at the latest. If you know the number of controls to create you can derive the ID from the counter variable by appending it to the control-id.
Recommandable readings:
TRULY Understanding Dynamic Controls
Page-Lifecycle
Or you use one of the builtin Data-Bound Control like Repeater that do this automatically. You only have to set their DataSource and call DataBind().
Here are answers of me on similar questions with implementation details:
C#
VB.NET (+ C#)

Dynamically add WebUser Controls in a loop

hi I like to add Dynamically add WebUser Controls in a loop
like this con1 con2 con3 and more or less depending on the loop
is there a good way to do this
my first try look like this. but i don't know how to tell it to use the next one grpCon2
foreach (DataRow Group in AllGroups.Rows)
{
GroupListControl grpCon1 = new GroupListControl();
grpCon1.NickName = "STUFF";
grpCon1.GroupName = "HARD";
LiteralAddCOntrols.Text = #"<uc1:GroupListControl ID=""GrpCOn1"" runat=""server"" />";
}
You need to use loadcontrol(pathtoyourusercontrol), and then and the control back to your page at the location you want.
sharedUC uc = (sharedUC)LoadControl("~/sharedUC/control.ascx");
plcContent.Controls.Add(uc);
Add :
To the page aspx loading the control and you will be able to use a typed reference to it.
You can do that, but you have to remember two things:
You have to give them ID - and remember them in a Session
When the controls do any PostBack actions (like Click) - you have to refresh the exact collection on every post back in Page_PreInit event (which normaly the framework does) - because the attached event won't fire.
And the Page_PreInit have to refresh the exact collection with the same ID-s.
It's possible but it's not so simple at the beginning.
And here is a detailed description how to do that.
https://web.archive.org/web/20211031102347/https://aspnet.4guysfromrolla.com/articles/092904-1.aspx
You can use this way and use "updatePanel" to dynamically change your controllers:
here I use "userControls_DeviceController" as my Usercontroller Class name.
userControls_DeviceController FAN1;
userControls_DeviceController FAN2;
protected void Page_Load(object sender, EventArgs e)
{
FAN1 = (userControls_DeviceController)LoadControl("~/userControls/DeviceController.ascx");
saloon.Controls.Add(FAN1);
FAN2 = (userControls_DeviceController)LoadControl("~/userControls/DeviceController.ascx");
saloon.Controls.Add(FAN2);
}
and also for customizing your usercontrol you can put a timer on your page and use an updatepanel to change properties of the specify usercontrol.
protected void Timer1_Tick(object sender, EventArgs e)
{
int counter = Convert.ToInt32(Session["c"]);
FAN1.SetDeviceIndex(counter);//here I change usercontrol picture FAN1
FAN2.SetDeviceIndex(counter);//here I change usercontrol picture FAN2
counter++;
if (counter == 4)//I have 4 picture to changing.
{
counter = 0;
}
Session["c"] = counter;
UpdatePanel1.Update();
}
I hope it could help you ...

Categories