How do edit controls that were created in C# during runtime? - c#

So i have this block of code and i have a button called AddNewButton which adds a StackPanel into a already created StackPanel called MainStackPanel which is irrelevant but the "GroupPanel" has child controls such as "GroupName", "GroupTextBox" and "GroupEdit".
Now the "GroupEdit" button has a click event that runs the void named "GroupEdit_Click" and in that void i use Button GroupEdit1 = sender as Button; Now this works and makes me able to access the buttons properties and change content but my problem is: How do i access the other controls such as "GroupPanel", "GroupName" and "GroupTextBox". I will use the AddNewButton a few times so when i access the separate controls they need to be accessed seperately
I tried to get rid of as much unnecessary code.
private void AddNewButton_Click(object sender, RoutedEventArgs e)
{
StackPanel GroupPanel = new StackPanel();
TextBlock GroupName = new TextBlock();
GroupName.Text = "Group ";
TextBox GroupTextBox = new TextBox();
GroupTextBox.Visibility = Visibility.Collapsed;
Button GroupEdit = new Button();
GroupEdit.Content = "Edit Group";
GroupEdit.Click += new RoutedEventHandler(GroupEdit_Click);
GroupPanel.Children.Add(GroupName);
GroupPanel.Children.Add(GroupTextBox);
GroupPanel.Children.Add(GroupEdit);
}
private void GroupEdit_Click(object sender,RoutedEventArgs e)
{
Button GroupEdit1 = sender as Button;
GroupEdit1.Content = "Done";
//Now how do i access these controls?
GroupName.Visibility = Visibility.Collapsed;
GroupTextBox.Visibility = Visibility.Visible;
}
}

You could maintain a private List of your dynamically added GroupEdit controls and assign them numbered tags.
private List<TextBox> dynamicGroupEdits = new List<TextBox>();
private void AddNewButton_Click(object sender, RoutedEventArgs e)
{
...
dynamicGroupEdits.Add(GroupEdit);
GroupEdit.Tag = dynamicGroupEdits.Count;
GroupPanel.Tag = GroupEdit.Tag;
GroupTextBox.Tag = GroupEdit.Tag;
...
}
private void GroupEdit_Click(object sender,RoutedEventArgs e)
{
...
tag = GroupEdit1.Tag;
// Loop through all child controls and set visibility according to tag
for each (var c in LogicalTreeHelper.GetChildren(GroupEdit1.Parent)
{
if(c is TextBox && c.Tag == tag)
c.Visible =Visibility.Visible;
else if(c is TextBlock && c.Tag == tag)
c.Visibility = Visibility.Collapsed;
}
}

Related

User control is added/removed based on checkbox state. If it's checked the user control added correctly but not working for removal

I have tried with the following code but still, it adds the user control without any issue but removal is not happening
private void objCheckBox_CheckedChanged(object sender, EventArgs e)
{
LabelWdTxtBox objLblWdTxtBox = new LabelWdTxtBox();// user control instance created
objLblWdTxtBox.Controls[1].Name = ((ButtonBase)sender).Text;
objLblWdTxtBox.Controls[1].Text = ((ButtonBase)sender).Text;
objLblWdTxtBox.Controls[0].Name = ((ButtonBase)sender).Text;
if (((CheckBox)sender).CheckState == CheckState.Checked)
{
flowLayoutUserControl.Controls.Add(objLblWdTxtBox);//adding the user control to panel
}
else if (((CheckBox)sender).CheckState == CheckState.Unchecked)
{
flowLayoutUserControl.Controls.Remove(objLblWdTxtBox);//Removing the user control to panel
objLblWdTxtBox.Dispose();
}
flowLayoutUserControl.Refresh();
// flowLayoutUserControl.ResumeLayout(false);
}
I would store the control in the .Tag property so you don't have to keep re-creating and disposing of it each time:
private void objCheckBox_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
if (cb.CheckState == CheckState.Checked)
{
if (cb.Tag == null)
{
LabelWdTxtBox objLblWdTxtBox = new LabelWdTxtBox();// user control instance created
objLblWdTxtBox.Controls[1].Name = ((ButtonBase)sender).Text;
objLblWdTxtBox.Controls[1].Text = ((ButtonBase)sender).Text;
objLblWdTxtBox.Controls[0].Name = ((ButtonBase)sender).Text;
cb.Tag = objLblWdTxtBox;
}
flowLayoutUserControl.Controls.Add(cb.Tag); //adding the user control to panel
}
else
{
if (cb.Tag != null)
{
flowLayoutUserControl.Controls.Remove(cb.Tag); //Removing the user control to panel
}
}
}
Is the goal to remove the textbox after the user un-checks a checkbox ? Remove textbox completely from the controls or make it invisible?
Assuming there's a checkbox control on the form called cb_User and a textbox control tb_Input needs to be added/removed from the form
private void cb_User_CheckedChanged(object sender, EventArgs e)
{
var checkbox = (CheckBox)sender;
if (checkbox.Checked)
{
var tb_Input = new TextBox();
tb_Input.Name = "tb_Input";
this.Controls.Add(tb_Input);
}
else
{
var tb_Input = this.Controls.Find("tb_Input", true).First();
this.Controls.Remove(tb_Input);
}
}
The thing that needs to happen is finding the textbox control that was added earlier to the form and removing that instance from the Form, which is what this.Controls.Find() does - it finds the added control by name (notice it has a name property set)

Use Panel.Click (of Dynamic Panels) event on Button.Click C# Windows Forms

I have Dynamically generated panels on my Form, every panel has multiple controls including TextBoxes, ComboBoxes and Buttons. I want to catch their values on a "Save" Button which is not dynamically generated (its in the form). I'm getting the Values with this code:
private void GetPanelControls(object sender, EventArgs e)
{
Panel allpanels = sender as Panel;
panelname = ItemsIDSelected[panelnamecounter] + "p";
//"p" identifies Panel and there is a counter with a list
if (allpanels.Name == panelname)
{
foreach (Control item in allpanels.Controls)
{
if (item.Name == (ItemsIDSelected[panelcontrolcounter] + "t")) //"t" identifies TextBox
{
ItemsNameListforInsert.Add(item.Text);
panelcontrolcounter++; //Panel has multiple controls
}
panelnamecounter++; //There are multiple Panels
}
}
}
How can I call this event on my Button_Click Event??
Panel panelGroup = new System.Windows.Forms.Panel();
panelGroup.Click += new EventHandler(GetPanelControls);
This is how Im Generating Panels and its event.
you can try something like this
private void Button_Click(object sender, EventArgs e)
{
GetPanelControls(this, new EventArgs());
}
EDIT
What if we use a method for this without using panel click event, if you need you can call this method inside the panel click event
private void GetPanelControls()
{
foreach (Control formControl in this.Controls)
{
if (formControl is Panel)
{
string panelName = ItemsIDSelected[panelnamecounter] + "p";
if (formControl.Name == panelName)
{
foreach (Control item in formControl.Controls)
{
// Your Code
}
}
}
}
}
//Control create button
private void button1_Click(object sender, EventArgs e)
{
Panel pnl = new Panel();
pnl.Name = "pnltest";
pnl.Location = new Point(500, 200);
TextBox txt1 = new TextBox();
txt1.Name = "txttest";
txt1.Location = new Point(0 ,10);
pnl.Controls.Add(txt1);
ComboBox cmb = new ComboBox();
cmb.Location = new Point(0, 50);
cmb.Name = "cmbtest";
cmb.Items.Add("one");
cmb.Items.Add("two");
cmb.Items.Add("three");
pnl.Controls.Add(cmb);
Button btn = new Button();
btn.Name = "btntest";
btn.Text = "submit";
btn.Location = new Point(0, 75);
btn.Click += btn_Click;
pnl.Controls.Add(btn);
this.Controls.Add(pnl);
}
//control button click event
void btn_Click(object sender, EventArgs e)
{
foreach (Control frmcntrl in this.Controls)
{
if (frmcntrl is Panel)
{
if (frmcntrl.Name == "pnltest")
{
foreach (Control item in frmcntrl.Controls)
{
if (item is TextBox)
{
if (item.Name == "txttest")
{
MessageBox.Show(item.Text .ToString());
}
}
else if (item is ComboBox)
{
if (item.Name == "cmbtest")
{
MessageBox.Show(item.Text);
}
}
}
}
}
}
}

Get child control content from sender

How do I get a value from the sender's children?
MouseUp on a Canvas creates a Grid.
private void ScrollViewer_MouseUp(object sender, MouseButtonEventArgs e)
{
Grid grid = new Grid();
Label timeLabel = new Label();
timeLabel.Content = "06:00"; //this could be anything
timeLabel.Name = "TimeStart"
grid.Children.Add(timeLabel);
canvas.Children.Add(grid);
grid.MouseDown += new MouseButtonEventHandler(ClickEvent);
}
When the user clicks on an already existing Grid, I want a MessageBox containing timeLabel.Content to appear, in this case, "06:00"
This is not working (I've tried some others as well, same result)
void ClickEvent(object sender, RoutedEventArgs e)
{
Grid test = (Grid)sender;
Label label = (Label)test.FindName("TimeStart");
MessageBox.Show(label.Content.ToString());
}
Error
An unhandled exception of type 'System.NullReferenceException' occurred in MissionControl M.exe
Additional information: Object reference not set to an instance of an object.
You Can use Registername for your label control and give a name, then access it using FindName
private void ScrollViewer_MouseUp(object sender, MouseButtonEventArgs e)
{
NameScope.SetNameScope(grid, new NameScope());
Label timeLabel = new Label();
timeLabel.Name = "label1";
grid.RegisterName("label1", timeLabel);
timeLabel.Content = "06:00";
}
void ClickEvent(object sender, RoutedEventArgs e)
{
Grid test = (Grid)sender;
if (test != null)
{
Label label = (Label)test.FindName("label1");
MessageBox.Show(label.Content.ToString());
}
}
You named your grid, yet you try to find your label by name. Pick one or the other. Probably, naming your label instead of your grid makes the most sense.
you should name you lable and then FindName
or you can use then first grid children :
Grid test = (Grid)sender;
if(test != null)
{
Label label = test.Children[0] as Lable;
MessageBox.Show(label.Content.ToString());
}

WPF / C# - Adding functionality to a button dynamically created inside a listbox

I have a button that adds this StackPanel to the listbox everytime it's clicked. In it is a button. I'm trying to figure out how to add code to this button that it's adding. Ideally I want the button to be a delete button, so it would delete that element (itself) in the list. I'm just trying to figure out how to add functionality to the button I'm dynamically creating. hope that makes sense
thanks for any help!
private void Button_Click_1(object sender, RoutedEventArgs e)
{
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = System.Windows.Controls.Orientation.Horizontal;
CheckBox checkBox = new CheckBox();
checkBox.IsChecked = true;
TextBox textBox = new TextBox();
textBox.Width = 100;
textBox.Text = textBox1.Text;
Button button = new Button(); //HOW DO I ADD CODE TO THIS BUTTON?
stackPanel.Children.Add(checkBox);
stackPanel.Children.Add(textBox);
stackPanel.Children.Add(button); //HOW DO I ADD CODE TO THIS BUTTON?
listBox1.Items.Add(stackPanel);
}
You can programatically add a click handler to the button like this:
Button button = new Button(); //HOW DO I ADD CODE TO THIS BUTTON?
button.Click += btn_Click;
stackPanel.Children.Add(checkBox);
stackPanel.Children.Add(textBox);
stackPanel.Children.Add(button); //HOW DO I ADD CODE TO THIS BUTTON?
and then you need the click event handler
void btn_Click(object sender, System.Windows.RoutedEventArgs e)
{
// your code to execute when the button is clicked.
stackPanel.Items.Remove(button);
}
Try This.
Add Stackpanel that have textblock and Button
private void OnSaveClick(object sender, RoutedEventArgs e)
{
StackPanel stp = new StackPanel();
stp.Orientation = Orientation.Horizontal;
stp.Children.Add(new TextBlock()
{
Text = string.Format("Item {0}", lstitems.Items.Count),
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch
});
Button btn = new Button();
btn.Content = string.Format("Delete Item {0}", lstitems.Items.Count);
btn.Height = 25;
btn.Width = 100;
btn.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
btn.Click += btnDeleteClick;
stp.Children.Add(btn);
lstitems.Items.Add(stp);
}
Delete Button Click handler
void btnDeleteClick(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
if (btn != null)
{
var st = FindParent<StackPanel> (btn); //stackpanel as we have added item as stackpanel.
if (st != null)
lstitems.Items.Remove(st);
}
}
To Find the Type to Object in the Visual Tree.
public T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(dependencyObject);
if (parent == null) return null;
var parentT = parent as T;
return parentT ?? FindParent<T>(parent);
}
That is the simplest setup. Ideally you want more error handling etc.
Button button = new Button();
button.Click += (s, args) => { listBox1.Items.Remove(stackPanel); };

WPF how do I create a textbox dynamically and find the textbox on a button click?

I am creating a TextBox and a Button dynamically using the following code:
Button btnClickMe = new Button();
btnClickMe.Content = "Click Me";
btnClickMe.Name = "btnClickMe";
btnClickMe.Click += new RoutedEventHandler(this.CallMeClick);
someStackPanel.Childern.Add(btnClickMe);
TextBox txtNumber = new TextBox();
txtNumber.Name = "txtNumber";
txtNumber.Text = "1776";
someStackPanel.Childern.Add(txtNumber);
I hook up to a click event to the Click Me button. The click me button even is fired correctly. However I cannot find the TextBox I entered dynamically.
Here is my click me event:
protected void ClickMeClick(object sender, RoutedEventArgs e)
{
// Find the phone number
TextBox txtNumber = this.someStackPanel.FindName("txtNumber") as TextBox;
if (txtNumber != null)
{
string message = string.Format("The number is {0}", txtNumber.Text);
MessageBox.Show(message);
}
else
{
MessageBox.Show("Textbox is null");
}
}
How can I find the TextBox txtNumber?
Josh G had the clue that fixed this code: use RegisterName().
Three benefits here:
Doesn't use a member variable to save the reference to the dynamically created TextBox.
Compiles.
Complete code.
using System;
using System.Windows;
using System.Windows.Controls;
namespace AddControlsDynamically
{
public partial class Window1 : Window
{
public void Window_Loaded(object sender, RoutedEventArgs e)
{
GenerateControls();
}
public void GenerateControls()
{
Button btnClickMe = new Button();
btnClickMe.Content = "Click Me";
btnClickMe.Name = "btnClickMe";
btnClickMe.Click += new RoutedEventHandler(this.CallMeClick);
someStackPanel.Children.Add(btnClickMe);
TextBox txtNumber = new TextBox();
txtNumber.Name = "txtNumber";
txtNumber.Text = "1776";
someStackPanel.Children.Add(txtNumber);
someStackPanel.RegisterName(txtNumber.Name, txtNumber);
}
protected void CallMeClick(object sender, RoutedEventArgs e)
{
TextBox txtNumber = (TextBox) this.someStackPanel.FindName("txtNumber");
string message = string.Format("The number is {0}", txtNumber.Text);
MessageBox.Show(message);
}
}
}
Another method is to set the associated TextBox as Button Tag when instanciating them.
btnClickMe.Tag = txtNumber;
This way you can retrieve it back in event handler.
protected void ClickMeClick(object sender, RoutedEventArgs e)
{
Button btnClickMe = sender as Button;
if (btnClickMe != null)
{
TextBox txtNumber = btnClickMe.Tag as TextBox;
// ...
}
}
You can get your original click handler to work by registering the name of the text box:
someStackPanel.RegisterName(txtNumber.Name, txtNumber);
This will then allow you to call FindName on the StackPanel and find the TextBox.
If you want to do a comprehensive search through the visual tree of controls, you can use the VisualTreeHelper class.
Use the following code to iterate through all of the visual children of a control:
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parentObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is TextBox)
// Do something
}
If you want to search down into the tree, you will want to perform this loop recursively, like so:
public delegate void TextBoxOperation(TextBox box);
public bool SearchChildren(DependencyObject parent, TextBoxOperation op)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
TextBox box = child as TextBox;
if (box != null)
{
op.Invoke(box);
return true;
}
bool found = SearchChildren(child, op);
if (found)
return true;
}
}
Is there any way you can make the TextBox control a field in your class instead of a variable inside your generator method
public class MyWindow : Window
{
private TextBox txtNumber;
public void Window_Loaded()
{
GenerateControls();
}
public void GenerateControls()
{
Button btnClickMe = new Button();
btnClickMe.Content = "Click Me";
btnClickMe.Name = "btnClickMe";
btnClickMe.Click += new RoutedEventHandler(this.CallMeClick);
someStackPanel.Childern.Add(btnClickMe);
txtNumber = new TextBox();
txtNumber.Name = "txtNumber";
txtNumber.Text = "1776";
someStackPanel.Childern.Add(txtNumber);
}
protected void ClickMeClick(object sender, RoutedEventArgs e)
{
// Find the phone number
string message = string.Format("The number is {0}", txtNumber.Text);
MessageBox.Show(message);
}
}

Categories

Resources