Mike Taulty's Blog
Bits and Bytes from Microsoft UK
Windows 8.1: ListViews, GridViews, ListViewItemPresenter, GridViewItemPresenter

Blogs

Mike Taulty's Blog

Elsewhere

Archives

Once upon a time, I wrote a post about using Blend to explore the templates that you find in a ListBox in Silverlight as part of a series of a bunch of posts I wrote about using Blend. – some of those would be out of date today with respect to Windows 8.1 Store or Windows 8.0 Phone applications but some of them more than likely still apply.

Today I got a mail from a developer about a scenario where you have a Windows 8.1 Store app which has a ListView like this one;

    <ListView>
      <ListView.Items>
        <x:String>One</x:String>
        <x:String>Two</x:String>
        <x:String>Three</x:String>
      </ListView.Items>
      <ListView.ItemTemplate>
        <DataTemplate>
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="1"
                       Text="{Binding}" 
                       VerticalAlignment="Center"/>
            <Ellipse Grid.Column="0"
                     Width="48"
                     Height="48"
                     Margin="5"
                     Fill="Red" />
          </Grid>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>

which displays as below;

image

and at runtime if I hover over one of those items they look as below where the mouse is hovering over item “Two” in the list;

image

So…where is that grey selection rectangle coming from? As talked about in that previous Blend post, it’s coming from the ItemContainerStyle but in a Windows Store app this is done a little differently from how it was done for a Silverlight app that I wrote about in that previous article. In fact, I think it’s possibly being done differently in Windows 8.1 from how it was done in Windows 8.0.

If I open up this project in Blend and edit the ItemContainerStyle;

image

then that copy of the ItemContainerStyle presents a mysterious beast – the ListViewItemPresenter;

image

What’s that? I think it’s new in Windows 8.1 and looks to have arrived with its friend GridViewItemPresenter. Normally when editing one of these things I’d perhaps expect to see some kind of template containing at least a ContentPresenter and then a bunch of other UI pieces that are shown/hidden depending on the visual state of the ListViewItem (i.e selected, focused, etc).

However, this ListViewItemPresenter isn’t such a deviation away from that sort of idea because it is itself derived from ContentPresenter and it looks like it exists to package up that functionality into a handy control by adding a whole bunch of properties such as these brushes;

image

so it would seem that rather than setting up a visual state to change a foreground colour when an item is selected it’s possible to just set the SelectedForeground property and presumably the ListViewItemPresenter is doing its own work to monitor for state changes and is then applying that Foreground brush as appropriate.

For example, if I change that SelectedForeground to be Red and then select an item;

image

it’s clear what effect that has had and I haven’t had to go and play around with any visual states. Similarly, if I want to lose that visual tickmark on the end of a selected item;

image

Then there’s just a property to turn off;

image

rather than me having to do lots of work with visual states and various elements in a control template.

Taking a look at the runtime elements that this way of working creating using the always excellent XAML Spy reveals what’s actually present in the tree of elements;

image

and I can see that I have a ListViewItem containing a ListViewItemPresenter which then contains the elements from my DataTemplate – kind of as expected.

What’s also interesting is that if I select the first item in the list and then have a look at the properties of the ListViewItem and the ListViewItemPresenter representing that item;

image

image

Then I can clearly see that the ListViewItemPresenter has set its own Foreground property to Red based on the item being selected and the value of the SelectedForeground property.

The TextBlock within my DataTemplate therefore paints its Text using a red brush because it is picking up that Foreground property from its parent ListViewItemPresenter.

The specific question I got from a developer though was how an element like the Ellipse in the DataTemplate up above at the top of this post could pick up that same modified value of Foreground and use it as its Fill property when it is part of the content displayed for the selected item.

That is, if the Ellipse was originally coloured white;

            <Ellipse Grid.Column="0"
                     Width="48"
                     Height="48"
                     Margin="5"
                     Fill="White" />

then when it is the selected item, it stays white;

image

which isn’t a surprise in itself because it’d be asking a lot for it to pick up the value of the “ambient” Foreground property and apply it to its own Fill property.

How could that value be picked up though and applied to that Ellipse? “Not very easily” seemed to be the answer that I came up with.

My first thought was to attempt to tie together the Ellipse and the TextBlock via ElementName binding. That is;

image

But that doesn’t work. What I seem to see happening is that when I select an item in the ListView, sure enough the Foreground of the TextBlock changes to Red. However, the Ellipse remains unchanged.

I suspect this is because the TextBlock.Foreground property isn’t explicitly set. That TextBlock is picking up an “ambient” Foreground value from its parent which will be the ListViewItemPresenter and that control looks to replace the value of its Foreground property with the value of its SelectedForeground property for an item that is selected. However, I don’t think the change in that property is going to flow through to the Ellipse because of the ambient way in which it’s being picked up.

As an aside, I found it a bit odd that the ListViewItemPresenter seems to be an “all or nothing” sort of control. I partly expected to be able to edit its template and see the various UI pieces that it was made up of but I don’t seem to be able to do that.

What I seem to need is to be able to bind the Fill of my Ellipse to the ListViewItemPresenter.Foreground property. The blocker to that is that t the Ellipse is in a DataTemplate and the ListViewItemPresenter is present in the ControlTemplate for the ListViewItems that are being dynamically created at runtime by the control.

There’s not really a link to be made between those two things in the XAML. They exist without knowledge of each other (or at least I think they do).

One way for the Ellipse to reach out and bind to that ListViewItemPresenter would be with an “ancestor” style binding but, in Windows 8.1 apps, I don’t have the ability to use a RelativeSource binding with the Mode=Ancestor so I can’t just set up a binding on the Ellipse which goes up the tree of elements trying to find a ListViewItemPresenter. I think that I need to find another way to make the binding.

My best “solution” so far is to make the Brush in question part of the “viewmodel”. That is, if I make a little view model class like this with change notification;

  class DataItem : ViewModelBase
  {
    public DataItem()
    {

    }

    public string Label
    {
      get
      {
        return (this._label);
      }
      set
      {
        base.SetProperty(ref this._label, value);
      }
    }
    string _label;


    public Brush HighlightBrush
    {
      get
      {
        return (this._highlightBrush);
      }
      set
      {
        base.SetProperty(ref this._highlightBrush, value);
      }
    }
    Brush _highlightBrush;

  }

then I can change my XAML such that my ListView is using these DataItems for its Items and such that my Ellipse is binding its Fill to this HighlightBrush;

  <ListView ItemContainerStyle="{StaticResource ListViewItemStyle1}">
      <ListView.Items>
        <local:DataItem Label="One" />
        <local:DataItem Label="Two" />
        <local:DataItem Label="Three" />
      </ListView.Items>
      <ListView.ItemTemplate>
        <DataTemplate>
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="1"
                       Text="{Binding Label}"
                       VerticalAlignment="Center"
                       x:Name="txtBlock" />
            <Ellipse Grid.Column="0"
                     Width="48"
                     Height="48"
                     Margin="5"
                     Fill="{Binding HighlightBrush, TargetNullValue=White}" />
          </Grid>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>

and I can change my ItemContainerStyle such that the ListViewItemPresenter is binding its Foreground property to this HighlightBrush too in a 2-way manner;

image

and that seems to “kind of work” in the sense that the colour of my Ellipse and my TextBlock seem to track each other when an item is selected;

image

but it feels a bit clunky and I wonder whether there might not be a better way of getting this kind of binding to work in this situation?

Any suggestions? Maybe I got drawn in and missed something obvious? Drop me a line via the comments below.


Posted Sat, Dec 7 2013 1:17 AM by mtaulty
Filed under: , , , ,

Comments

MSDN UK Team blog wrote Windows 8.1: ListViews, GridViews, ListViewItemPresenter, GridViewItemPresenter
on Sat, Dec 7 2013 1:30 AM

Once upon a time, I wrote a post about using Blend to explore the templates that you find in a ListBox

Jason Haley wrote Interesting Finds: December 7, 2013
on Sat, Dec 7 2013 1:43 PM

Interesting Finds: December 7, 2013

Hamish wrote re: Windows 8.1: ListViews, GridViews, ListViewItemPresenter, GridViewItemPresenter
on Sun, Dec 8 2013 9:18 AM

Thnaks Mike - I enjoy the explorations through the sometimes mysterious land of Xaml, especially with the new things that have come out in Windows 8.1.  

Glen wrote re: Windows 8.1: ListViews, GridViews, ListViewItemPresenter, GridViewItemPresenter
on Tue, Dec 10 2013 1:14 PM

Nice article Mike,

Would be nice if you could push to get all the binding types (RelativeSource) from SL \ WPF added to 8.1.

Seeing how 8.1 apps are rumoured to be allowed to run on the desktop in the next release (Threshold) it would be nice to get all the nice xaml time savers at the same time.

mtaulty wrote re: Windows 8.1: ListViews, GridViews, ListViewItemPresenter, GridViewItemPresenter
on Wed, Dec 11 2013 4:09 PM

Glen,

Personally, I'd like to see the Windows XAML platform grow a number of features from SL/WPF as I find it a bit challenging when I have a use case for a feature that isn't present for Windows 8.1 apps but has been built in one of the previous frameworks. It always feels awkward to be hoping for a feature that's already been implemented elsewhere.

On the 'threshold' side of things - I've seen those rumours as well but have genuinely no clue as to whether that's happening or not.

Mike