Link to home
Start Free TrialLog in
Avatar of avtel
avtel

asked on

How to refer to a Dynamically Created TextBlock later on to change its text?

Hi,

In an event handler in the code-behind, I created TextBlocks using a for-loop, and added them to cells in a grid.  Now, I want to be able to refer to them later on in a different event handler, and iterate through another for-loop to change each one's Text value to something else

My problem is that I can't seem to refer to the specific TextBlocks in any way.  I've searched through a lot of sites/forums/posts, but just can't seem to find something that'll work.  Can anyone help?
for (int i = 0; i < 6; i++)
			{
				for (int j = 1; j < 13; j++)
				{
					TextBlock genericTextBlock = new TextBlock();
					genericTextBlock.Name = "TextBlock" + j.ToString() + i.ToString();
					genericTextBlock.FontSize = 40;
					genericTextBlock.VerticalAlignment = VerticalAlignment.Center;
					genericTextBlock.HorizontalAlignment = HorizontalAlignment.Center;
					genericTextBlock.Foreground = new SolidColorBrush(Colors.White);
					Grid.SetColumn(genericTextBlock, j);
					Grid.SetRow(genericTextBlock, i);

Open in new window

Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Create a List and add them to it:

    List TextBlocks = new List();

    ...
        TextBlock genericTextBlock = new TextBlock();
        ...
        TextBlocks.Add(genericTextBlock);

Now you can use that list to iterate over them:

    foreach(TextBlock tb in TextBlocks)
    {
        tb.xxx = yyy;
    }

Put the List at the CLASS level, outside the method where the TextBlocks were created, so it will be accessible.

*I don't code in WPF, though, so I can't get more specific than that.  =\
for (int k = 1; k < 13; j++)
{
   TextBlock txt = FindControl("TextBlock" + k.ToString()) as TextBlock;  // you will need to tweak this a little.  Just pass the
                                                                                                              // same name you created earlier.
   txt.Text = "Assign any new value desired here";
}

private Control FindControl(string sControlName)
{
    if (sControlName.Length == 0 || this.Controls.Find(sControlName, true).Length == 0)
       return null;
    else
       return this.Controls.Find(sControlName, true)[0];
}
   
HTH
Ashok
for (int k = 1; k < 13; j++)
{
   TextBlock txt = FindControl("TextBlock" + k.ToString()) as TextBlock;  // you will need to tweak this a little.  Just pass the
                                                                                                              // same name you created earlier.
   if (txt != null)  // this should not occur if you pass correct name as you created.
      txt.Text = "Assign any new value desired here";
}

private Control FindControl(string sControlName)
{
    if (sControlName.Length == 0 || this.Controls.Find(sControlName, true).Length == 0)
       return null;
    else
       return this.Controls.Find(sControlName, true)[0];
}
   
HTH
Ashok
Avatar of avtel
avtel

ASKER

ashol111:

I tried your method, and got the following exceptions:

"'MyProg.MainWindow' does not contain a definition for 'Controls' and no extension method 'Controls' accepting a first arguemnt of type 'MyProg.MainWindow' could be found (are you missing a using directive or an assembly reference?)"

and

"Cannot convert type 'System.Windows.Controls.Control' to 'System.Windows.Controls.TextBlock' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion"
private Control FindControl (string sControlName)
		{
			if (sControlName.Length == 0 || this.Controls.Find(sControlName, true).Length == 0)
				return null;
			else
				return this.Controls.Find(sControlName, true)[0];
		}		

		private void ModeListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
		{
			// TODO: Add event handler implementation here.
			
			// This creates a holder ListBoxItem to take the SelectedItem from the ListBox.  The "sender as ListBox" marks the generic object sender as the ListBox to get SelectedItem as, and "SelectedItem as ListBoxItem" gets the response as a ListBoxItem?? 
			ListBoxItem holderLBImode = ((sender as ListBox).SelectedItem as ListBoxItem);
			
			switch (holderLBImode.Content.ToString())
			{
				case "Show All" :
				{
					if (TuningListBox.SelectedIndex != -1)
					{	
						InitializeTunings();
						break;
					}
					else
						break;
				}
				case "Hidden" :
				{					
					
					for (int l = 0; l < 6; l++)
					{
						
						for (int m = 1; m < 13; m++)
						{
							TextBlock tempTB = FindControl("TextBlock" + m.ToString() + l.ToString()) as TextBlock;
							tempTB.Text = "WORKS";
						}
						
					}						
					break;

Open in new window

Try using FindName():
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.findname.aspx

Maybe something like?

    for (int i = 0; i < 6; i++)
    {
        for (int j = 1; j < 13; j++)
        {
            TextBlock tb = (TextBlock)this.FindName("TextBlock" + j.ToString() + i.ToString());  
            // ...use "tb" somehow...
        }
    }
Avatar of avtel

ASKER

Idle_Mind:

I tried that and get the following error:

"Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object."
Avatar of avtel

ASKER

Idle_Mind:

I tried that and get the following error:

"Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object."
That means the control wasn't found...not sure how to proceed as I have done almost no WPF programming and I'm not sure how it's laid out.  
Instead of "this", try putting the name of your grid:

    TextBlock tb = (TextBlock)NameOfGridHere.FindName("TextBlock" + j.ToString() + i.ToString());  
Idle_Mind is right.  If control is not directly on the form, change this to where the control is.
If it is inside a GRID, change it to GRID.

Ashok
BTW, I recently did a WinForms application where I used FindControl without any problem.  The code I posted is tested in my application.

Ashok
I'm not sure you can use FindControl() in a WPF application...I need to play with it more!  =\
With wpf this method (FindControl) is now called FindName but it always returns a null.

Ashok
ASKER CERTIFIED SOLUTION
Avatar of Ashok
Ashok
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of avtel

ASKER

I had tried using the name of the Grid (and every other possible parent control) that directly contains the TextBlocks, but that returned the same exception.  I just can't think of anything else to try.
Would it help if I posted my entire code-behind and the XAML?
I should mention I'm using Expression Blend 3 as the design editor.

Also, I tried Idle_Mind's List method, and got it to work for this particular situation.  I'd still prefer to be able to refer to specific textblocks by the name I assign at creation though (since it is named according to row and column of the grid it's in).  With the List method, I can refer by index, but correlating that to the textblock in a particular grid position isn't as smooth.

I'm dying to figure this out, because it has come up more than once.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of avtel

ASKER

Ok, that sounds like a good alternative.  I'll give it a try and report back.  I'm not sure what to do with the points here - I really want to figure out the FindName method, but your alternatives do what I need...I'm not sure how important the points are, but if they are important, what's the protocol?

By the way, what's the name of the WPF book you're reading?  I'd like to find a good source to get a better handle on what I'm doing.
I just started "WPF in Action" by Arlen Feldman and Maxx Daymon.  I'm a WinForms guy so I'm stumbling around in WPF at the moment...LOL.

If someone posts the correct method on how to use FindName() then by all means give them the points!  =)

A split is usually never objected to by participants though.  I almost always give points to everyone involved in questions I ask but it's not necessary.