views:

26

answers:

1

Ok... this is sort of a two-parter here. (Sort of. May actually just be one. That's what I'm hoping anyway.)

First, more generally, is it possible to target, via XAML only, a named item in a control's template? For instance, if a control's template has a ContentPresenter named 'PART_Foo' and we want to specifically set the HorizontalAlignment on that specific item to 'Stretch' via pure styling, can it be done? I know we can do this in the OnApplyTemplate override of a subclass where we explicitly search for the control by name then set the property in code, but again, we're hoping for a XAML-only solution so we can do this strictly via styling and not subclasses, which are mostly discouraged anyway except for specific use-case scenarios.

Also, we do not want to have to manually specify the template for the control as we want the current theme to determine what that template is and thus how the control appears. We just want to say 'In whatever template the theme has chosen, if there's a part named 'foo', set this property on it via pure styling. If a part with that name isn't found, do nothing!

The desire for a XAML-only approach is more because of the second part, which is we're targeting a generated container object, not the control itself, meaning it wouldn't be a straight subclass anyway as we'd have to muck around with ItemcontainerGenerators and such, which is a real pain in the a$$, especially when the ItemsControl is virtualized.

For specifics, our ultimate goal is to single out the Border named 'Bd' in a TreeView's TreeViewItem's template and set its attached property 'Grid.ColumnSpan' to '2' instead of its default of '1'. That's it! It amazes me how something so simple seems damn near impossible without manually replacing the entire TreeViewItem's template or resorting to a code-behind-based solution.

A: 

No, this is not possible using XAML only. You would at least have to write an attachted property for this (wich you then could use in XAML). And that would only work if you do not have any controls being created on the fly at runtime as it happens in virtualized lists. It would look something like this: c:TemplateHelper.ReplaceStretchForTemplateItemName="PART_Foo". In the changed handler you would walk the visual sub tree of that control using VisualTreeHelper and look for that name and apply whatever you want.

Modifying the a template like this is flawed tough and considered to be bad practise. It is very likeley that there is a theme or will be in the future that does not have "Part_Foo" or that "Part_Foo" is something completely different than you expected it to be. Themes and thus the ControlTemplates are subject to change. New themes will appear (and automatically applied to your application) as Microsoft updates its operating systems and if you support custom themes you designers might come up with a theme that is different.

You could argue that this a disadvantage of ControlTemplates and it to some extend it is. But then again try customizing Controls in windows forms (or any other UI framework on this planet)... It's just that when getting used to the immense felxibilty of WPF it's harder to accept limitations, which in this case are by design.

bitbonk
I'm fine with the caveats of targeting a control that may or may not be there because the only other option, replacing the TreeViewItem's control template completely busts the ability to theme the control anyway! If we place the style in local resources, it'll override the theme, and if we place it where it can be themed, this may break our design by not guaranteeing the child gets stretched in the first place. The only good thing is the odds of theming a TreeViewItem are small since the only visual is the button and the background highlight. Everything else is position-related.
MarqueIV
I still can't believe there's no 'full-row select' option on the TreeView and that you have to go through all these hoops to create it! Crazy!! One thing though... I did look into attached properties but don't see how that can be used with a container-based items control. I mean you have to set the property when the container is created which is driven by its data source, not just when you set the property on the control itself, so you're right back to a subclass nightmare.
MarqueIV
Have you tried setting that property in the `ItemsContainerStyle`? I would assume it should be applied when the the TreeViewItem has been created. You might run into some issues though, when you have virtualization enabled.
bitbonk
@BitBonk: Do you mean use an attached property in the ItemsContainerStyle itself? That may give em what I'm looking for so long as that property does get set on every created TreeViewItem class, which, considering all other properties would, just very well may do the trick! (I don't yet have enough points to vote up your comment (it's not an answer where I could) but know I wanted to!
MarqueIV