views:

97

answers:

3

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!

+1  A: 

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.

Evan Hutnick
Great solution to my question. Now let's pretend I asked the question I really meant, check out my edit.
JGord
A: 

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();
AnthonyWJones
I get the error message IEnumerable dependency object does not contain a definition for TypeOf
JGord
@JGord: Ensure you have included the `using System.Linq` at the top of you code file.
AnthonyWJones
Already had that in there, other possible pitfalls?
JGord
@JGord: Oops, my bad! its `OfType` not `TypeOf`, edited accordingly.
AnthonyWJones
A: 

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.

Steve Danner