tags:

views:

2544

answers:

5

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 even of 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?

+1  A: 

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);
    }
}
bendewey
This will work. However is there no way to find it? What happens if I have say 10 textboxes? Is the solution to create a List<Textbox> and just use Linq to find them?
David Basarab
I accepted this answer because it does work, and if I have 10 textboxes I can create a list and find them in a list.Thanks.
David Basarab
The code does not compile: Childern, CallMeClick not defined, etc.
hughdbrown
someStackPanel would have to be setup in your Xaml. This code is based on the sample provide in the OPs question.
bendewey
The List<Textbox> should work fine, your still just keeping a local reference to the control.
bendewey
+1  A: 

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;
        // ...
    }
}
Tyalis
This also works.
David Basarab
+2  A: 

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;
    }
}
Josh G
+2  A: 

Josh G had the clue that fixed this code: use RegisterName().

Three benefits here:

  1. Doesn't use a member variable to save the reference to the dynamically created TextBox.
  2. Compiles.
  3. 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);
            }
        }
    }
    
hughdbrown
This works out quite well. I changing this to the accepted answer because it does what I originally wanted. The other works well too, but I did not want to create textbox and store them.
David Basarab
+3  A: 

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