views:

413

answers:

3

Here's the deal. I can create a ListBox and style it. I can edit a copy of the template such that the States become available in Expression Blend 3. And I can change the state so that the background color of a line item is modified when selected. But I cannot change the foreground color of the text because of the ContentPresenter! Does anyone have any example XAML that shows how to accomplish this seemingly easy task?

The answer seems to lie in removing the ContentPresenter and replacing it with with some sort of ListBoxItem style or template but this is where I get stuck. The ContentPresenter of the ListBox refers to some other template "{TemplateBinding Template}" - where is that? Also, when I try to modify ContentPresenter in any way, the States panel goes blank and I am left with a morass of XAML. Fortunately, there's CTRL-Z!

I really think Microsoft has to rethink the XAML approach or make Blend a much more complete tool. The way it should work is that I should be able to click on ANY element and define states for it. If I am trying to break the rules, Blend should tell me this and offer a way to fix it. Just having the States panel go empty is not helpful.

+1  A: 

Ordinarily the ListBox is not responsible for the content of the items themselves including what Foreground color, if needed, they use. The items could be a series of images in which case Foreground is meaningless. The items could be a complex multi-element UI containing various different text items each needing different Foreground colors, so again the idea of ListBox supplying a single Foreground color is meaningless.

This is why the default template for the Item container use a ContentPresenter, which basically means "place arbitary item content here".

If you wanted to create a new style for list boxes in general to use for their container item styles then you would have to accept this limitation, your VSM cannot know the details of the contained item.

However if you are creating a container style for a specific instance of ListBox and you understand the type and nature of the items being presented then you do not need to keep the ContentPresenter in the template. You can replace directly with what ever Xaml you need to present each item.

For example you could replace the ContentPresenter in the Xaml with this:-

<Grid Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}">
    <TextBlock x:Name="ContentItem" Text="{Binding Property1, Mode=OneWay}" TextWrapping="Wrap" Foreground="#FFDC1C1C"/>
</Grid>

Note that the Padding and HorizontalAlignment of the items are the same as those used by the presenter. In this case I'm using as single TextBlock called "ContentItem" and binding it to the source objects Property1 property.

Now that the template contains a named TextBlock for displaying the item, I can fiddle with the VSM to modify its Foreground for various different Visual states.

AnthonyWJones
I replaced the ContentPresenter with a custom DataTemplate comprised of a user control. This control has a textblock. For VSM to work, I somehow have to get a reference to the actual custom control instance when listbox raises the SelectionChanged event. This is problematic. The VSM.GoToState method needs the instance passed to it so that it can work. I can't seem to get the reference. Ideas? I agree that you should be able to 'fiddle with the vsm' to make this work but should is the optimal word, here. I have yet to see anyone do it, though.
Wade
Now, I can capture each custom DataTemplate instance into an array during the control's Loaded event and then use numerical indexes to find the instance based on the parent ListBox's SelectedIndex property but this is hardly scalable.
Wade
Well, I did find a way to do it w/o using VSM but it eliminates the ability to play animations. I changed to Foreground of the textblock to {TemplateBinding Foreground} and then set Foreground on the ListBoxItem. Sigh....
Wade
See, this is interesting. Virtually no one responding to what has to be a very common issue. This is why I think either a) the VSM is not always a practical way to go, esp with List controls or b) it is just too complicated to wire this stuff up or c) MS needs to modify the object model / tree a bit in order to exposed the items that are attached via the custom templates.I found a very interesting article here (http://blog.avanadeadvisor.com/blogs/markti/archive/2008/05/03/11060.aspx) that holds promise, though.
Wade
A: 

Sorry to resurrect an old question, but I got stuck on the very same issue and found a solution. I'll share it as who knows, it may be useful to someone.

It's really simple: if you replace the ContentPresenter in your template with a ContentControl, then it works (ContentControl has a Foreground property).

Francesco De Vittori
A: 

Ah, cool! Thanks for the feedback. I think I ended up making a user control and exposing a public Foreground property that set the color but I can't remember. Your answer combined with the earlier one is really helpful.

As an aside, I did break down and learn to make my own custom controls with dependency properties and the whole 9 yards and, man, lemme tell you, it was well worth it. I feel like I can do anything with WPF/SL now.

Wade