WPF how do I create a textbox dynamically and find the textbox on a button click?
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;
}
}
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.
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;
// ...
}
}