I'm working on a project and I'm in a situation where the administrator needs to accept new users into the system. I've got a form that only admins can access, which shows a list of all the waiting applicants. I've found out how to create buttons at run time and how to add an event handler for the click event, but the handler requires a method by the same name to run.
Obviously I can't just put code for a method inside a for loop, unless I'm mistaken. How would I give the program the ability to support an potentially infinite amount of applicants?
void AcceptUsersAdminLoad(object sender, EventArgs e)
{
//FOR LOOP - To be finished. Will read an xml file to find out # to loop.
Button newButton = new Button();
newButton.Click += new System.EventHandler(newButtonClick);
newButton.Text = "Accept";
Panel1.Controls.Add(newButton);
}
private void newButtonClick (Object sender, System.EventArgs e){
}
This works, but as I've said, only for one button. As relatively painless as it would be to copy the method and append it's name with a number a hundred times, I'd prefer to find a way with support for more.
You can use that same method for all of your buttons! The sender parameter will tell you which button is the source, simply cast it to a button. You can store an ID of some sort in the .Tag() property of the button so you know who you are working with (when you create them, assign it).
private void newButtonClick (Object sender, System.EventArgs e){
Button btn = (Button)sender;
// ... do something with "btn" in here ...
}
Answer to the titular question: You don't create methods in a loop. You will occasionally create anonymous methods in a loop, but save that for later :).
To do what you want though: When you generate these buttons, they should all be pointing to the same event handler. The logic you want to run is the same, but the data is different.
How you get the data to the function is not trivial, one (hackish) way to do it is to store the related object (or its index) in the Tag property of the button, which you can then retrieve via the sender argument of the event handler.
Related
I know about this question but it does not addres my issue.
Suppose we have two buttons that do the very same thing (load csv file and feed the data in two variables) but on two different sets of variables. I can write two functions dedicated to both functions, but they will share too much common code.
How can I detect what button called the callback function to decide what set of variables to work on?
You can access the Button by casting the sender argument.
You should use an explicit cast instead of (the often seen) as operator, because it would correctly result in an InvalidCastException when the sender is unexpectedly not a Button.
private void button_Click(object sender, EventArgs e)
{
var button = (Button)sender;
// Use button properties to differentiate and load to your variables accordingly
}
I define a button like this:
Button info = new Button();
info.Command += Button_Command;
info.CommandName = "handleinfoclick";
info.CommandArgument = id;
And I tried to write a command handler here:
private void Button_Command(object sender, CommandEventArgs e)
{
Debug.WriteLine("HERE IN BUTTON COMMAND");
}
But the command handler is not being called. I have worked on this for a while and I haven't been able to find a solution. The button has to be defined in the codebehind because it is on a dynamic table and the function it calls will need the commandargument to interact with that row's data.
If it is web forms, then assigning server events dynamically will no work. I think the best approach is to assign events statically in your code and use some variables to define specific status. Then you can set the variables values and process them inside event and make decision to do some work.
What do sender and eventArgs mean/refer to? How can I make use of them (for the scenario below)?
Scenario:
I'm trying to build a custom control with a delete function, and I want to be able to delete the control that was clicked on a page that contains many of the same custom control.
The sender is the control that the action is for (say OnClick, it's the button).
The EventArgs are arguments that the implementor of this event may find useful. With OnClick it contains nothing good, but in some events, like say in a GridView 'SelectedIndexChanged', it will contain the new index, or some other useful data.
What Chris is saying is you can do this:
protected void someButton_Click (object sender, EventArgs ea)
{
Button someButton = sender as Button;
if(someButton != null)
{
someButton.Text = "I was clicked!";
}
}
sender refers to the object that invoked the event that fired the event handler. This is useful if you have many objects using the same event handler.
EventArgs is something of a dummy base class. In and of itself it's more or less useless, but if you derive from it, you can add whatever data you need to pass to your event handlers.
When you implement your own events, use an EventHandler or EventHandler<T> as their type. This guarantees that you'll have exactly these two parameters for all your events (which is a good thing).
Manually cast the sender to the type of your custom control, and then use it to delete or disable etc. Eg, something like this:
private void myCustomControl_Click(object sender, EventArgs e)
{
((MyCustomControl)sender).DoWhatever();
}
The 'sender' is just the object that was actioned (eg clicked).
The event args is subclassed for more complex controls, eg a treeview, so that you can know more details about the event, eg exactly where they clicked.
'sender' is called object which has some action perform on some
control
'event' its having some information about control which has
some behavoiur and identity perform
by some user.when action will
generate by occuring for event add
it keep within array is called event
agrs
FYI, sender and e are not specific to ASP.NET or to C#. See Events (C# Programming Guide) and Events in Visual Basic.
In C# if you create an object on a button click, at the end of the click event, the object is no longer in scope. How do I create an object on the click of a button, but release it on the click of another button. Here is what I am trying to do:
Build an application that accepts user data and adds it to a database. The application contains two classes: Personal information and employer information. The personal information class object should be created when the "Start Application" button is pressed. The application then opens a tab that requests personal information. If the "Add Employer" button is selected, an instance of Employer is created. After they press submit at the end, it should close the one or two objects and return to the main menu. When the next person presses the button, it should go through the process again.
I can create objects on click or in the class itself, but how do you limit the life of the object between to button presses?
Thanks!
Use a class-scoped data member. Very quick example:
public class MyClass
{
private Foo foo;
private void Button1_Click(object sender, EventArgs e)
{
this.foo = new Foo();
}
private void Button2_Click(object sender, EventArgs e)
{
// I can access this.foo here. I can also dispose of it
// if it is IDisposable and/or I can set it to null.
// To check if button 1 was pressed, check to see if the object
// is null (if it is, button 1 wasn't pressed)
}
}
You can do this by defining one of the event handlers anonymously inside of the other event handler:
void button1_Click(object sender, EventArgs e)
{
Foo data = new Foo();
EventHandler handler = null;
handler = (s, args) =>
{
//Use Foo here
DoStuff(data);
button2.Click -= handler;
};
button2.Click += handler;
}
Note that we need to do some extra work to make sure to remove the event handler when it is clicked here. If you don't need to do that, then it does simplify the code.
Here the anonymous method is closing over the local variable, which will extend that variable's lifetime for the lifetime of the anonymous method. This approach, unlike those using a field, actually creates a variable who's lifetime lasts until the next button is clicked, and doesn't leave a variable lying around with a meaningless value before the first button is clicked or after the second is clicked.
Sounds like you're wanting to use properties?
Here's a link to MSDN, but there's lots out there if you just Google'C# properties'
I can create objects on click or in the class itself, but how do you limit the life of the object between to button presses?
Sadly you're pretty much stuck with putting it at class scope. There is no simply way to limit the scope of an object to just a few methods within a class. If your 2 event handlers can access your Employer, then so can every other method within the class. You just have to not use it.
However, out of curiosity I managed to hack around and produce the effect you want. I did a class with 2 event handlers, one for each button, as well as a private Employer variable.
public class ButtonHandler
{
private Employer employerData;
public void button1_Click(object sender, EventArgs e)
{
employerData = "set data here";
}
public void button2_Click(object sender, EventArgs e)
{
employerData = "use / clear data here";
}
}
Then I went to my Form.Designer.cs and manually changed the button.Click event handler from the default this.btnLoadPlaylist_Click to my functions within the ButtonHandler class above. The problem with this is it gets deleted every time the Designer.CS is regenerated by Visual Studio. So the effect is possible, just not convenient with the tools we are given.
This question already has answers here:
Is it possible to avoid multiple button clicks on a Winform?
(3 answers)
Closed 2 years ago.
I have an app with many user controls and many buttons on each, each button has an OnClick event which does some important stuff and then sends to a new user control.
The problem comes when the user clicks really fast multiple times, the event code gets executed more than once before exitting to a new user control, causing problems.
My current solution is to disable the button on the very first line of the event handler, but doing this to every window and handler would be troublesome, what can I do?
EDIT: Would it be a good solution to derive from Button, and override the OnClick event so it always does a check for a "working" variable, and if it is true, it doesnt start the event ? Something like:
public class MyButton : Button
{
private static bool isWorking = false;
protected override void OnClick(EventArgs e)
{
if (!isWorking)
{
isWorking = true;
base.OnClick(e);
isWorking = false;
}
//Else do nothing
}
}
You can use some timeStamp to delay between 2 clicks:
DateTime timeStamp;
//this will handle the clicks with the allowed interval being 0.5 second
//Note that a tick is equal to 1/10,000,000 of second.
private void click_Handler(object sender, EventArgs e) {
if ((DateTime.Now - timeStamp).Ticks < 5000000) return;
timeStamp = DateTime.Now;
//your code goes here ....
}
If you want all buttons to wait until one button's work is done, add a bool isProcessing variable to your form. Wrap the work of each button inside an if (!isProcessing), and set that flag to true in the first line inside the if statement. Then don't forget to set it back to false right before you exit the if.
I'm assuming you're doing all of this asynchronously, since if it's all in the same thread, the form will lock while it's processing the work. This will solve your issue though.
Disabling controls while sensitive operation is on-going is a typical solution that I always apply.
But since there can be quite a few controls on one screen that are affected by some click or change in UI, I typically design forms to have a specialized method which walks through all the affected controls and disables/enables them accordingly.
Something like this:
void EnableControls(bool enable)
{
foreach (Control ctl in this.Controls)
ctl.Enabled = enable;
}
Similarly, you could group controls into related buckets, so to disable/enable only one of them etc. Depends on your precise needs.
There is an alternative solution to use timer - disable the button, but enable it after 1 sec. This prevents nervous users from clicking multiple times if that would cause damage to data (i.e. each click is treated as a new operation).
I would call the same function from every button and then perform the specific task:
private void Button_Click(object sender, EventAgrs e)
{
Button btn = sender;
btn.disable = true;
switch (btn.AccessibleName)
// call specific function for the particular button or do it all here
}
I'm not sure if this would even work, but just an idea...
You could try with aspect oriented approach (with the help of Postsharp for example):
Create two aspects, one for method entry and one for method exit. In the method entry mark the current method as 'processing' (add the method name to a hash set for example). In the method exit mark the method as 'not processing' (remove it from the hash set). Then in the method entry check if the method is processing and if it is, then cancel the method (like this: https://stackoverflow.com/a/2437794/113858)
Mark all of your event handlers with this aspect.