Cleverguy25
Cleverguy25

Reputation: 503

ItemsControl and ItemTemplateSelector in Windows 10 UWP app

I did a little WPF programming a long time ago, but I am just returning to xaml with UWP, but I think this should work and cannot figure out why. Basically I want to use an ItemsControl (because I just want to list some data, I don't want selection) instead of a ListView control. Here are my resources:

<Page.Resources>
    <DataTemplate x:Key="SentMessageDataTemplate">
        <TextBlock Text="Sent" />
    </DataTemplate>
    <DataTemplate x:Key="ReceivedMessageDataTemplate">
        <TextBlock Text="Recieved" />
    </DataTemplate>
    <services:MessageDataTemplateSelector x:Key="MessageDataTemplateSelector" ReceivedTemplate="{StaticResource ReceivedMessageDataTemplate}" SentTemplate="{StaticResource SentMessageDataTemplate}"></services:MessageDataTemplateSelector>
</Page.Resources>

Here is my ItemsControl:

<ItemsControl ItemsSource="{Binding Messages}" ItemTemplateSelector="{StaticResource MessageDataTemplateSelector}" />

Here is my DataTemplateSelector:

public class MessageDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate SentTemplate
    {
        get;
        set;
    }

    public DataTemplate ReceivedTemplate
    {
        get;
        set;
    }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        var message = item as MessageViewModel;
        if (message == null)
        {
            return this.SentTemplate;
        }

        return message.Sent ? this.SentTemplate : this.ReceivedTemplate;
    }
}

Instead of displaying either of my templates it just displays my ViewModel type name (so basically ToString).

However if I switch it from ItemsControl to ListView, it works fine.

Any suggestions?

Upvotes: 12

Views: 7875

Answers (4)

beatnikthedan
beatnikthedan

Reputation: 221

Here is what the documentation says:

Remarks

If your ItemsControl.ItemsPanel is an ItemsStackPanel or ItemsWrapGrid, provide an override for the SelectTemplateCore(Object) method. If the ItemsPanel is a different panel, such as VirtualizingStackPanel or WrapGrid, provide an override for the SelectTemplateCore(Object, DependencyObject) method.

Upvotes: 1

Petter Hesselberg
Petter Hesselberg

Reputation: 5498

Interesting -- ListView and GridView both invoke the template selector; plain ItemsControl or ListBox do not.

Overriding the other SelectTemplateCore method in the template selector helps, e.g.:

protected override DataTemplate SelectTemplateCore(object item)
{
    var message = item as MessageViewModel;
    if (message == null)
    {
        return SentTemplate;
    }

    return message.Sent ? SentTemplate : ReceivedTemplate;
}

protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
    return SelectTemplateCore(item);
}

The latter method is called in all cases; the first isn't called for ItemsControl items. This page provides an explanation of sorts:

If your ItemsControl.ItemsPanel is an ItemsStackPanel or ItemsWrapGrid, provide an override for the SelectTemplateCore(Object) method. If the ItemsPanel is a different panel, such as VirtualizingStackPanel or WrapGrid, provide an override for the SelectTemplateCore(Object, DependencyObject) method.

Upvotes: 5

Kory Gill
Kory Gill

Reputation: 7163

Use this override instead:

protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)

This is the one that gets called, not the one without the 2nd parameter.

Upvotes: 16

TheOliver
TheOliver

Reputation: 120

Maybe you should use <TextBlock Text="{Binding Sent}" /> You don't bind anything in your Template.

Upvotes: 0

Related Questions