generate a delegate for a Button-Click Event - c#

I simply want to create a list of Buttons. But each button should do something different.
Its just for training. I'm new to C#.
what I have right now:
for (int i = 0; i < answerList.Count; i++)
{
Button acceptButton = new Button { Content = "Lösung" };
acceptButton.Click += anonymousClickFunction(i);
someList.Items.Add(acceptButton);
}
I want to generate the Click-Function like this:
private Func<Object, RoutedEventArgs> anonymousClickFunction(i) {
return delegate(Object o, RoutedEventArgs e)
{
System.Windows.Forms.MessageBox.Show(i.toString());
};
}
/// (as you might see i made a lot of JavaScript before ;-))
I know that a delegate is not a Func... but I don't know what I have to do here.
But this is not working.
Do you have any suggestions how i can do something like this?
EDIT: Solution
I was blind ... didn't thought about creating a RoutedEventHandler :-)
private RoutedEventHandler anonymousClickFunction(int id) {
return new RoutedEventHandler(delegate(Object o, RoutedEventArgs e)
{
System.Windows.Forms.MessageBox.Show(id.ToString());
});
}

I'm assuming you want an array of functions, and you want to get the function by index?
var clickActions = new RoutedEventHandler[]
{
(o, e) =>
{
// index 0
},
(o, e) =>
{
// index 1
},
(o, e) =>
{
// index 2
},
};
for (int i = 0; i < clickActions.Length; i++)
{
Button acceptButton = new Button { Content = "Lösung" };
acceptButton.Click += clickActions[i];
someList.Items.Add(acceptButton);
}

Hmm, what you could do. Is the following, plain and simple.
for (int i = 0; i < answerList.Count; i++)
{
var acceptButton = new Button { Content = "Lösung" };
acceptButton.Click += (s, e) => MessageBox.Show(i.ToString());
someList.Items.Add(acceptButton);
}

you can use lambda expressions for anonymous methods:
for (int i = 0; i < answerList.Count; i++)
{
Button acceptButton = new Button { Content = "Lösung" };
acceptButton.Click += (sender, args) => System.Windows.MessageBox.Show(i.toString());
someList.Items.Add(acceptButton);
}

Related

add total sum of rows in a datagridview in a label

I have a label as a Subtitle, in this label i want to display the number of rows in datagridview.
i added this line of code but it just returns a 0 not the amount of rows in the datagridview.
private void Form_Load(object sender, EventArgs e)
{
lblTitle.Text = _settings.set;
lblSubtitle.Text = dataGridView1.RowCount.ToString();
}
why is it displaying only a 0?
Requirement
DataGridView
Select Column Name Which you want to sum
A Label need in which you save the Result
SelectAmount is Label
private void function()
{
int SelectResult = 0;
if (DataSelector.RowCount != 0)
{
for (int i = 0; i < DataSelector.RowCount; i++)
{
bool value = false;
if (DataSelector.Rows[i].Cells["Select"].Value != null)
{
value = (bool)DataSelector.Rows[i].Cells["Select"].Value;
if (value)
{
int ar = 0;
bool r = int.TryParse(DataSelector.Rows[i].Cells["Paid"].Value.ToString(), out ar);
if (r)
{
SelectResult += ar;
}
}
}
}
}
SelectAmount.Text = SelectResult.ToString();
}
Use RowsAdded and RowsRemoved events for updating label with new value
public class YourForm
{
public YourForm()
{
InitializeComponent();
UpdateSubtitle(); // Display initial value
dataGridView1.RowsAdded += (sender, args) => UpdateSubtitle();
dataGridView1.RowsRemoved += (sender, args) => UpdateSubtitle();
}
private void UpdateSubtitle()
{
lblSubtitle.Text = dataGridView1.RowCount.ToString();
}
}

C# - Button Click Event Programmatically Iteration [duplicate]

This question already has answers here:
Closures in C# event handler delegates? [duplicate]
(5 answers)
Closed 6 years ago.
I am trying to add some buttons to a control programmatically using a for-statement.
What I wish to accomplish is that every button fires the click event with the iterator value inside.
Here is an example of my code:
public class Foo
{
public Foo(int val)
{
//Do something with val
}
}
//for-statement
for(int i = 0; i < 5; ++i)
{
var button = new Button();
button.Click += (sender, e) =>
{
var text = new Foo(i);
}
}
In my scenarios it intializes Foo with the last value of the iterator, that being 4.
How can I accomplish to send every value of the iterator?
Button1->Click->Foo(0)
Button2->Click->Foo(1)
... and so on.
You fall in the trap of closures. Use Button.Tag instead.
public class Foo
{
public Foo(int val)
{
//Do something with val
}
}
//for-statement
for(int i = 0; i < 5; ++i)
{
var button = new Button();
button.Tag = i;
button.Click += (sender, e) =>
{
var text = new Foo((int)((sender as Button).Tag));
}
}
You can add a Tag to your Button like this
for(int i = 0; i < 5; ++i)
{
var button = new Button();
button.Tag = i;
button.Click += Button_Click();
}
And then cast object sender back to Button to receive the tag
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var tag = (int)button.Tag;
}
It's a well known problem, which is hard to find in fact (I fail to find something simple, therefore writing an answer). Change your for to capture loop variable value inside:
for(int i = 0; i < 5; ++i)
{
var current = i; // capture ('for' scope local variable to hold current value of i)
var button = new Button();
button.Click += (sender, e) => var text = new Foo(current); // don't use i here
}

Change button content in WPF

I have:
private void button1_MouseEnter(object sender, EventArgs e)
{
for (int i = 0; i > 2; i++)
{
button1.Content = Convert.ToString(i);
System.Threading.Thread.Sleep(1000);
}
tekst.Text = "Mouse Enter";
}
When I enter on Button I see only Mouse Enter, but Content on Button don't change. Why? What I can do wrong?
Hi is your for loop correct? It should be i<2 instead of i>2
for (int i = 0; i < 2; i++)
{
Your for loop never execute because you have wrong condition, change it to following code:
for (int i = 0; i < 2; i++)
Also you should use BackgroundWorker (msdn) to update your GUI dynamicly.
private void button1_MouseEnter(object sender, MouseEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
for (int i = 0; i < 2; i++)
{
this.Dispatcher.Invoke((Action)(() => { btn.Content = Convert.ToString(i); }));
System.Threading.Thread.Sleep(1000);
}
};
worker.RunWorkerCompleted += delegate { tekst.Text = "Mouse Enter"; };
worker.RunWorkerAsync();
}

Sending a variable in a C# EventHandler?

How can I send a variable with a newly created EventHandler?
The code I have is something like:
for (int i = 0; i < 5; i++)
{
Button buttonX = new Button();
buttonX.Location = new Point(0, 0 + offset);
buttonX.Size = new Size(310, 48);
buttonX.Click += new EventHandler(buttonClick);
}
private void buttonClick(object sender, EventArgs e)
{
MessageBox.Show();
}
How can I can make it like
buttonX.Click += new EventHandler(buttonClick , i);
private void buttonClick(object sender, EventArgs e, int i)
{
MessageBox.Show(i.toString());
}
Closures are grand. You can use lambda notation:
buttonX.Click += (sender, e) => buttonClick(sender, e, i);
or anonymous delegate notation:
buttonX.Click += delegate (object sender, EventArgs e) { buttonClick(sender, e, i); };
However, you're going to have trouble if you capture the loop variable.
Instead, do
for (int i = 0; i < 5; i++)
{
Button buttonX = new Button();
buttonX.Location = new Point(0, 0 + offset);
buttonX.Size = new Size(310, 48);
var i_copy = i;
buttonX.Click += (sender, e) => buttonClick(sender, e, i_copy);
}
Given your scenario, just utilize the Tag property; don't mix the solution with the Click event; you don't need to "pass" i every time to the event; just tag it to the control since it's always the same; that way you don't have to worry about closure.
Change your code to this:
for (int i = 0; i < 5; i++)
{
Button buttonX = new Button();
buttonX.Location = new Point(0, 0 + offset);
buttonX.Size = new Size(310, 48);
buttonX.Click += new EventHandler(buttonClick);
buttonX.Tag = i;
}
private void buttonClick(object sender, EventArgs e)
{
MessageBox.Show(((Button)sender).Tag.ToString());
}
You would create a class derived from EventArgs that carries the additional data points that you want.
http://msdn.microsoft.com/en-us/library/system.eventargs.aspx
So instead of just using EventArgs you would create an EventArgs for the event you are raing.
public class ButtonClickedEventArgs : EventArgs
{
public int EventInteger { get; private set; }
public ButtonClickedEventArgs(int i)
{
EventInteger = i;
}
}
And then when you raise the event you would create the ButtonClickedEventArgs class and pass that with the EventHandler.
You can't do that, but what you can do is use an intermediate lambda:
for (int i = 0; i < 5; i++)
{
int j = i; // Need to do this to fix closure issue
Button buttonX = new Button();
buttonX.Location = new Point(0, 0 + offset);
buttonX.Size = new Size(310, 48);
buttonX.Click += (sender, e) => {
buttonClick(sender, e, j);
};
}
private void buttonClick(object sender, EventArgs e, int i)
{
MessageBox.Show(i.toString());
}

Add Arrays of C# button Click in code in Run Time

To create Button and its click event in run time I use:
Button b = new Button();
b.Name = "btn1";
b.Click += btn1_Click;
But now I have an array of Buttons to create in run time; how to set each button's event - I cannot interpolate because it's not a string.
Button[] b = new Button(Count);
for (int i=0; i < Count; i++)
{
b[i] = new Button();
b[i].Name = "btn" + i;
b[i].Click += ??????
}
what should I do for "?????"
Option 1:
You can pass an lambda function, and create the handler based on the buttons index in the array like this:
for (int i=0; i < Count; i++)
{
b[i] = new Button();
b[i].Name = "btn" + i;
b[i].Click += (sender, args) =>
{
// your code
}
}
Option 2:
You can pass an anonymus delegate:
b[i].Click += delegate (sender, args) {
// your code
};
Option 3:
You can specify a handler function:
b[i].Click += YourHandlerFunction
// ....
// The handler signature also has to have the correct signature
void YourHandlerFunction(object sender, ButtonEventArgs args)
{
// your code
}
You can bind all buttons to the same event, so put the line like b[i].Click += button_Click;.
Then inside the button_Click event you can differentiate between the buttons, and take the proper actions.
For example:
public void button_Click(object sender, ButtonEventArgs e)
{
if( sender == b[0] )
{
//do what is appropriate for the first button
}
...
}
It depends on what you want to do! If you want to have the same method called for all clicks, do this:
Button[] b = new Button[Count];
for (int i=0; i < Count; i++)
{
b[i] = new Button();
b[i].Name = "btn" + i;
b[i].Click += OnClick
}
private void OnClick(object sender, RoutedEventArgs e)
{
// do something
}
If you want to do something different for each button, e.g. depending on the index, you can do something like this:
Button[] b = new Button[Count];
for (int i=0; i < Count; i++)
{
b[i] = new Button();
b[i].Name = "btn" + i;
b[i].Click += (s, e) => { /*do something*/ };
}

Categories