Adding dynamic buttons in WPF - c#

I made code that creates buttons dynamically, but how to assign different function to each button?
for (int i = 0; i < Buttons.Count; i++)
{
Button newBtn = new Button();
newBtn.Content = Buttons[i];
newBtn.Name = "Button" + i.ToString();
newBtn.Height = 23;
stackPanel1.Children.Add(newBtn);
newBtn.Click += new RoutedEventHandler(newBtn_Click);
}
private void newBtn_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello");
}
Now each button shows "Hello", but I wish it to be "Hello1", "Hello2"....ect.

if you could create a collection of objects with DelegateCommands or RelayCommand Property and DisplayName Property - you would just need a ItemsControl bind to this Collection and a DataTemplate for binding a button to Command and Text.
EDIT: just out of my head
public class MyCommandWrapper
{
public ICommand Command {get;set;}
public string DisplayName {get;set;}
}
in your viewmodel
public ObservableCollection<MyCommandWrapper> MyCommands {get;set;}
MyCommands.Add(new MyCommandWrapper(){Command = MyTestCommand1, DisplayName = "Test 1"};
...
in your xaml
<ItemsControl ItemsSource="{Binding MyCommands}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:MyCommandWrapper}">
<Button Content="{Binding DisplayName}" Command="{Binding Command}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
EDIT 2: if you need a new dynamic button - just add a new wrapper to your collection

for (int i = 0; i < Buttons.Count; i++)
{
Button newBtn = new Button();
newBtn.Content = Buttons[i];
newBtn.Height = 23;
newBtn.Tag=i;
stackPanel1.Children.Add(newBtn);
newBtn.Click += new RoutedEventHandler(newBtn_Click);
}
private void newBtn_Click(object sender, RoutedEventArgs e)
{
Button btn=sender as Button;
int i=(int)btn.Tag;
switch(i)
{
case 0: /*do something*/ break;
case 1: /*do something else*/ break;
default: /*do something by default*/ break;
}
}

Check the sender parameter of your newBtn_Click function. It should contain the instance of the button that was clicked. You can cast it to a button and check the name:
private void newBtn_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
if(btn != null)
{
MessageBox.Show(btn.Name);
}
}
If you don't want to check the Name property, you can also use the Tag property (http://msdn.microsoft.com/library/system.windows.frameworkelement.tag.aspx) to which you can assign an arbitrary object and check this later:
Button newBtn = new Button();
newBtn.Tag = i;
And later in the click handler:
private void newBtn_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
if(btn != null)
{
if(btn.Tag is int)
MessageBox.Show(String.Format("Hello{0}", btn.Tag));
}
}
I would prefer the solution with Tag because it's more safe than extracting something from a string.

newBtn.Click += new RoutedEventHandler((s,e) => MessageBox.Show("hallo"+((Button)s).Name);

private void newBtn_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
var buttonNumber = button.Name.Remove(0, 6);
MessageBox.Show("Hello" + buttonNumber);
}

Related

How to dynamically create buttons and add events to them?

I have array of buttons, and array of labels:
Label[] labels = new Label[10];
Button[] but = new Button[10];
While clicking the other button I want to dynamically create new button and new label from the array, i also want the but[i] to change the tex of labels[i]:
private void button1_Click(object sender, EventArgs e)
{
labels[i] = new Label();
labels[i].Location = new System.Drawing.Point(0, 15+a);
labels[i].Parent = panel1;
labels[i].Text = "Sample text";
labels[i].Size = new System.Drawing.Size(155, 51);
labels[i].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
a = labels[i].Height + labels[i].Top;
but[i] = new Button();
but[i].Text = "-";
but[i].Location = new System.Drawing.Point(0, labels[i].Height + labels[i].Top);
but[i].Parent = panel1;
but[i].Size = new System.Drawing.Size(155, 10);
but[i].Click += new System.EventHandler(but_Click);
i++;
}
private void but[i]_Click(object sender, EventArgs e)
{
labels[i].Text = "Changed Text";
}
But apparently I can't put an array in an event handler, how should I do it then?
One way to do this is to make your method return a handler instead of being a handler:
private EventHandler but_Click(int i)
{
return (s, e) => labels[i].Text = "Changed Text";
}
And use it like:
but[i].Click += but_Click(i);
Or do it inline:
but[i].Click += (s, ea) => labels[i].Text = "Changed Text";
What's happening in either of these is some compiler magic to capture the i variable. It's equivalent to this (which is also a valid, if verbose, way to do it):
class MyWrapper {
private int i;
public MyWrapper(int i) {
this.i = i;
}
public void TheHandler(object sender, EventArgs e) {
// TODO: capture the object that owns `labels` also, or this won't work.
labels[i].Text = "Changed Text";
}
}
//call with
but[i].Click += new EventHandler(new MyWrapper(i).TheHandler);
You could add the array index to the button as Tag property, and then pull it back out in but_Click.
So, add
but[i].Tag = i;
to the button creation. And then change the event handler:
private void but_Click(object sender, EventArgs e)
{
int buttonIndex = (int)((Button)sender).Tag;
labels[buttonIndex].Text = "Changed Text";
}
Or put the event handler inline:
but[i].Click += (s,e) => { label[i].Text = "Changed Text"; }
Or another option using the Tag property, add:
but[i].Tag = label[i];
...
private void but_Click(object sender, EventArgs e)
{
Label label = (Label)((Button)sender).Tag;
label.Text = "Changed Text";
}
Advantage of this approach is you're not relying on keeping arrays in synch after the initial creation of the controls.
I guess this is self-explaining:
public void SomeMehthod()
{
Button btn1 = new Button();
Button btn2 = new Button();
Button btn3 = new Button();
// Your button-array
Button[] btns = new Button[]
{
btn1,
btn2,
btn3
};
foreach(Button btn in btns)
{
// For each button setup the same method to fire on click
btn.Click += new EventHandler(ButtonClicked);
}
}
private void ButtonClicked(Object sender, EventArgs e)
{
// This will fire on any button from the array
// You can switch on the name, or location or anything else
switch((sender as Button).Name)
{
case "btn1":
// Do something
break;
case "btn2":
// Do something
break;
case "btn3":
// Do something
break;
}
}
Or if your array is accessible globaly:
Button[] btns = new Button[5];
Label[] lbls = new Label[5];
private void ButtonClicked(Object sender, EventArgs e)
{
Button clicked = sender as Button;
int indexOfButton = btns.ToList().IndexOf(clicked);
// ..IndexOf() returns -1 if nothign is found
if(indexOfButton > 0)
{
lbls[indexOfButton].DoWhatYouWant...
}
}

Attach event to dynamically created button click

I want to attach an event to a button clicked generated at runtime. Till this point I've wrote the code, but can't pass the button's ID to the method. Here is my code
This code does not through any error, another problem is after the click event the controls get washed away. How to prevent this ?
protected void Button1_Click(object sender, EventArgs e)
{
int i = int.Parse(TextBox1.Text);
for (int x = 1; x <= i; x++)
{
Button b = new Button();
b.ID = "btn_" + x.ToString();
b.Text = "btn_" + x.ToString();
b.Click += new System.EventHandler(myEventHandler);
pnlHolder.Controls.Add(b);
}
}
private void myEventHandler(object sender, EventArgs e)
{
txtMain.Text = sender.ToString(); // I want to know which button was pressed
}
try,
txtMain.Text = (sender as Button).Name;
or
txtMain.Text = (sender as Button).Text;
Try this
private void myEventHandler(object sender, EventArgs e)
{
Button b = (Button) sender;
txtMain.Text = b.ID;
//
txtMain.Text = b.Text;
if(b.ID == "button1")
doThis();
else if(b.ID == "button2")
doThat();
}

Get the name of a silverlight control in c#

I have created a number of silverlight buttons thus:-
string b = "Button";
for (int i = 0; i < 10; i++)
{
Button btn = new Button();
btn.Name = b+i.ToString();
btn.FontSize += 2;
btn.Content = "Click Me " ;
btn.Click += new RoutedEventHandler(btn_Click);
stack.Children.Add(btn);
}
LayoutRoot.Children.Add(stack);
In the button click event I want to get the name of the button that was pressed. I had hoped that
string snd = sender.ToString(); would yield the information but all it gives is System.Windows.Controls.Button. Can anyone please help. Thanks.
You need to cast sender to a button.
public void btn_Click(object sender, EventArgs e)
{
var btn = (Button)sender;
Console.WriteLine(btn.Name);
}
public void btn_Click(object sender, EventArgs e)
{
var b = sender as Button;
if (b != null)
{
var name = b.Name;
// do something with name
}
}
Try this:
(sender as Button).Name
source

How can I remove a dynamically created button?

I want to remove all children of a StackPanel except for a Label, but I can't get it to
remove a dynamically created Button.
<StackPanel Name="myStackPanel">
<Label Name="myLabel">Label text</Label>
<TextBlock Name="myTextBlock">TextBlock text</TextBlock>
</StackPanel>
private void button1_Click(object sender, RoutedEventArgs e)
{
Button buttonX= new Button();
buttonX.Name = "ButtonInstall";
buttonX.Content = "Click Me";
buttonX.Width = 150;
buttonX.HorizontalAlignment = HorizontalAlignment.Left;
buttonX.Click += new RoutedEventHandler(buttonX_Click);
myStackPanel.Children.Add(buttonX);
}
private void button2_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myStackPanel); i++)
{
Visual childVisual = (Visual)VisualTreeHelper.GetChild(myStackPanel, i);
string controlName = childVisual.GetValue(Control.NameProperty).ToString();
if (childVisual.GetType() != typeof(Label))
{
myStackPanel.Children.Remove((UIElement)childVisual);
}
}
For your example, it's not necessary to use the VisualTreeHelper:
List<UIElement> delItems=new List<UIElement>();
foreach(UIElement uiElement in myStackPanel.Children){
if(uiElement is Label) continue;
delItems.Add(uiElement);
}
foreach(UIElement delItem in delItems){
myStackPanel.Children.Remove(delItem);
}

C# create an array of controls

Is it possible to create an array of controls? Is there a way to get the index of a control if more than one of the controls in the array share the same event handler?
This is certainly possible to do. Sharing the event handler is fairly easy to do in this case because the Button which raised the event is sent as part of the event args. It will be the sender value and can be cast back to a Button
Here is some sample code
class Form1 : Form {
private Button[] _buttons;
public Form1(int count) {
_buttons = new Button[count];
for ( int i = 0; i < count; i++ ) {
var b = new Button();
b.Text = "Button" + i.ToString()
b.Click += new EventHandler(OnButtonClick);
_buttons[i] = b;
}
}
private void OnButtonClick(object sender, EventArgs e) {
var whichButton = (Button)sender;
...
}
}
Based on Kevins comment:
foreach(Button b in MyForm.Controls.OfType<Button>())
{
b.Click += Button_Click;
}
void Button_Click(object sender, EventArgs e)
{
Button clickedButton = sender as Button;
}

Categories

Resources