Access Element inside Silverlight DataTemplate
Asked Answered
P

5

5

I have not been able to find a clean solution to the following problem even though there are a few related questions already on SO.

If I have a data template that is being used multiple times, for example, a TreeViewItem.HeaderTemplate, how can I change something the template for only some of the TreeViewItems.

For example, let's say my TVI HeaderTemplate has a textblock and depending on the string, I want to make the fontweight bold.

I want to do something like this:

((TextBlock)myTreeView.Items.ElementAt(0).FindName("myTextBlock")).FontWeight = FontWeights.Bold;

Does anyone have a solution for this? --> Thanks Evan

Edit: Is there a way to write a generic function to get a control based on it's name even if it's in a data template?

LayoutRoot.FindName("myTextBlock"); would work if myTextBlock was not in a datatemplate. How can I write a findElementInDataTemplate(string elementName, string parentName) function?

The reason Evan's answer is not what I'm looking for is because I am developing a control. I want the application developer who uses my control to be able to change any element in the control. If I use Evan's solution, that would require the application developer to have access to all the templates in the control. Possible, but not ideal. Thanks!

Protomorphic answered 10/8, 2010 at 15:27 Comment(3)
If you have used a DataTemplate that contains a control called "myTextBlock" multiple times and then have some sort of LayoutRoot.FindName("myTextBlock") operation, which of the many controls called "myTextBlock" would you want that operation to return?Stinkpot
@Stinkpot Good point, edited to include a parentName parameter.Protomorphic
@AnthonyWJones: Normally two controls with name is not possible. if you keep two same name control in template, then template is considered to be wrong.Hueston
N
0

what version of silverlight is this? And what year of " Aug 10 at 18:55" is this post from?

in the current version of SL4 it does not seem to be there..

Nonmoral answered 21/12, 2010 at 8:15 Comment(0)
R
4

One way I have accomplished this is to store all the needed items in a class-level collection variable by using the Loaded event of the control. Take this DataTemplate for example.

<DataTemplate>
   ...
   <TextBlock Loaded="TemplateTextBlock_Loaded" />
</DataTemplate>

Then you use the Loaded event to load up some sort of collection for later use.

private List<TextBlock> templateTextBlocks = new List<TextBlock>();

private void TemplateTextBlock_Loaded(object sender, RoutedEventArgs e)
{
   TextBlock tb = sender as TextBlock;
   if (!this.templateTextBlocks.Contains(tb)) this.templateTextBlocks.Add(tb);
}

Of course, if you're going to be loading and unloading the control, this may not work well for you.

Radiolarian answered 10/8, 2010 at 18:55 Comment(1)
This works me, AnthonyWJones answer was useful when visual tree already generated, but this one works before that as wellFleisher
V
2

If you're using data binding, have you tried using a binding converter? In this case you would do something like...

FontWeight={Binding Path=TextProperty, Converter={StaticResource BoldConverter}}

And the converter would be along the lines of...

string myTestString = (string)value;
if (myTestString.Contains("Bob"))
    return FontWeights.Bold;
return FontWeights.Normal;

Which makes it less painful to try and root through the elements to locate a particular one.

Vogel answered 10/8, 2010 at 15:59 Comment(1)
Great solution to my question. Now let's pretend I asked the question I really meant, check out my edit.Protomorphic
S
1

My first reaction to such a requirement would be: are you really sure you want to be doing that? I would normally urge developers to look at the existing control patterns being used. In this case what you seem a Templated control would seem warranted.

Of course this doesn't provide the flexibility you are after. What you seem to be after is the "holy grail" of customisable controls, the desire to tweak any minor detail about the control without having to duplicate the entire template of the control. OF course this isn't really possible declaratively, if it were I'd dread the syntax and semantic rules that would govern it.

Having said that there are always exceptions. So I'll present a possible option despite feeling that you shouldn't be doing this.

This old answer provides a Descendents extension method allow you to enumerate controls across the object tree. Given an instance of a TreeViewItem you should be able to find the TextBlock you are after with:-

TextBlock tb = treeViewItem.Descendents()
                 .OfType<TextBlock>()
                 .Where(t => t.Name == "myTextBlock")
                 .FirstOrDefault();
Stinkpot answered 10/8, 2010 at 17:58 Comment(3)
I get the error message IEnumerable dependency object does not contain a definition for TypeOfProtomorphic
@JGord: Ensure you have included the using System.Linq at the top of you code file.Stinkpot
@JGord: Oops, my bad! its OfType not TypeOf, edited accordingly.Stinkpot
N
0

what version of silverlight is this? And what year of " Aug 10 at 18:55" is this post from?

in the current version of SL4 it does not seem to be there..

Nonmoral answered 21/12, 2010 at 8:15 Comment(0)
H
0

can also try this

TextBlock txtBlk = grd.FindName("txtBlkName") as TextBlock;

where grd = your root element (Parent of the element you are looking for)

Headwaters answered 26/7, 2011 at 7:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.