Matthew Lacey
Matthew Lacey

Reputation: 47

Which components of a ListView have to be explicitly provided when utilising Control Templates?

The solution to my question might just be specifically related to WPF ListViews, but it could also just be a control template issue in general. I don't know.

I have the following 3 property class, with overridden ToString method defined in my codebehind:

public class WorkListViewItem
{
    public int Id { get; set; }
    public string Namey { get; set; }
    public bool d { get; set; }

    public override string ToString()
    {
        return "ID: " + Id + "\r\nName: " + Namey + "\r\nd?:" + d.ToString();
    }
}

I have a working ListView defined in my markup, as well as Data Templates defined under the window's resources for all 3 class properties, and an array of WorkListViewItem defined under an all-parent grid's resources.

(DTNamey also has two-way binding, a textbox, and a TextChanged event attached, but that makes no difference to my issue)

Data Templates:

<DataTemplate x:Key="DTNamey" DataType="{x:Type local:WorkListViewItem}">
    <TextBox Text="{Binding Path=Namey, Mode=TwoWay}" Width="65" Foreground="BlueViolet" TextChanged="TextBox_TextChanged"/>
</DataTemplate>
<DataTemplate x:Key="DTId" DataType="{x:Type local:WorkListViewItem}">
     <TextBlock Text="{Binding Path=Id}" Foreground="GreenYellow"/>
</DataTemplate>
<DataTemplate x:Key="DTd" DataType="{x:Type local:WorkListViewItem}">
    <TextBlock Text="{Binding Path=d}" Foreground="BlueViolet"/>
</DataTemplate>

Data Array:

<x:Array Type="{x:Type local:WorkListViewItem}" x:Key="wvlis">
    <local:WorkListViewItem Id="1" Namey="Fred" d="True"/>
    <local:WorkListViewItem Id="2" Namey="Beef" d="True"/>
    <local:WorkListViewItem Id="3" Namey="Pork" d="False"/>
</x:Array>

ListView:

<ListView x:Name="listv" ItemsSource="{StaticResource wvlis}">            
    <!--This actually works-->
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Namey" Width="80" CellTemplate="{StaticResource DTNamey}"/>
            <GridViewColumn Header="Length" Width="60" DisplayMemberBinding="{Binding Namey.Length}"/>
            <GridViewColumn Header="D?" Width="60" CellTemplate="{StaticResource DTd}"/>
        </GridView>
    </ListView.View>
</ListView>

Now this all does exactly what I want it to: (I lack the reputation to post images, but trust me, it really does!)

It displays the 3 columns and a row for each element in the data array. Changes to the textboxes for Namey are reflected in the second column (Length), and all is well in the world.

The Issue:

However, that same ListView definition, when placed in a Control Template, displays no items. The columns display just fine, but no rows are shown.

Window Resources:

<!--This does not work-->
<ControlTemplate TargetType="ListView" x:Key="cmonnow">
    <ListView>
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Namey" Width="80" CellTemplate="{StaticResource DTNamey}"/>
                <GridViewColumn Header="Length" Width="60" DisplayMemberBinding="{Binding Namey.Length}"/>
                <GridViewColumn Header="D?" Width="60" CellTemplate="{StaticResource DTd}"/>
            </GridView>
        </ListView.View>
    </ListView>
</ControlTemplate>

Inside Grid:

<ListView x:Name="listv" ItemsSource="{StaticResource wvlis}" Template="{StaticResource cmonnow}">
</ListView>

My Efforts:

I have tried adding ItemsPresenter controls in the columns, which clashes with the column header definitions.

I've tried adding the ItemsPresenter under:

<ListView.Items>
    <ItemsPresenter/>
</ListView.Items>

I've tried setting the ListView's data context to: (totally incorrect, I'm sure)

<ListView DataContext="{Binding local:WorkListViewItem}">

I've even tried defining the ListView's ItemTemplate property.

I have been working at figuring this out for 3 days, and decided to turn to the internet for help.

So my question would be; which ListView properties are required to display the items collection when using Control Templates?

Thank you for your time.

Matthew

Update 29/09/2015

I've found that placing ItemsPresenter and ContentPresenter elements directly under the ListView tag, adds blank items that are correctly styled via the data templates.

Breakthrough!

I have found that by binding the template's ListView's ItemsSource property, to the ItemsSource provided, all the items are displayed, and all columns are correctly populated.

<ControlTemplate TargetType="ListView" x:Key="cmonnow">
    <ListView ItemsSource="{TemplateBinding ItemsSource}">
    ...
</ControlTemplate>

Upvotes: 1

Views: 87

Answers (1)

Matthew Lacey
Matthew Lacey

Reputation: 47

Figured it out

Boiling this down, it seems that the only component that is required to get a ListView control template to display data is the ItemsSource property of the template ListView.

The ListView View property does not need to be manually set in order to see items.

However, for custom objects such as mine, it may be advisable to override the ToString method, as this is what you will see without any further template definitions.

(On a side note, it was a little counter-intuitive to have to define a ListView inside a Control Template with its TargetType property set to "ListView", but you could count this as a requirement too)

Upvotes: 0

Related Questions