SmiLe SmiLe - 10 days ago 9
C# Question

TemplateSelector doesn't work

I have

Items Control
, but I want improve this code for working with different types of input data.

<Grid>
<ItemsControl x:Name="control"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ItemsSource="{x:Bind ItemsSource, Mode=OneWay}"
ItemTemplate="{x:Bind CellTemplate, Mode=OneWay, Converter={StaticResource SimpleSelector}}">

<!--I want make like this-->
<ContentControl VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
ContentTemplate="{Binding SelectedCollageTemplate, Converter={StaticResource CollageTemplateSelector}}" />
<!-- -->
<!--now I have this-->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:SimplePanel SelectedCollage="{Binding SelectedCollage, Mode=TwoWay}"
SelectedCollagePattern="{Binding SelectedCollagePattern}">
<controls:SimplePanel.Background>
<ImageBrush Stretch="Fill"
ImageSource="ms-appx:///Images/Background/5.jpg" />
</controls:SimplePanel.Background>
</controls:SimplePanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- -->
</ItemsControl>


</Grid>


As you can see I want change hardcode to more flexible way and use
Template selector


I create selector:

<templateSelector:CollageTemplateSelector x:Key="CollageTemplateSelector"
SimpleTemplate="{StaticResource SimpleTemplate}"
ShapeTemplate="{StaticResource ShapeTemplate}"/>


And added
DataTemplate
:

<DataTemplate x:Key="SimpleTemplate">
<controls:SimplePanel
SelectedCollage="{Binding SelectedCollage, Mode=TwoWay}"
SelectedCollagePattern="{Binding SelectedCollagePattern}">
<controls:SimplePanel.Background>
<ImageBrush Stretch="Fill"
ImageSource="ms-appx:///Images/Background/5.jpg" />
</controls:SimplePanel.Background>
</controls:SimplePanel>




My converter returns Simple Panel. But when I lauch it my
SimplePanel
doesnt start(I have break point on constructor) and part of code doesnt work. What is my problem?

Answer
  1. You're setting the ContentTemplate of your ContentControl to your selector; you should set the ContentTemplateSelector property instead.

  2. In your ItemsControl you're setting ItemsTemplate to something that looks like a template selector; you should set the ItemsTemplateSelector property instead.

  3. You shouldn't bind to template selectors, but access them as StaticResources.

I don't fully understand the details of what you're trying to do, so here's an example of a DataTemplateSelector that works.

To start with, I'm using the following ItemsSource, with the intent of making the string "Three" show in red:

public string[] ItemsSource => new[]
    {
        "One", "Two", "Three",
    };

The template selector has two DataTemplate properties that will be set from XAML -- one for "Three" strings; another for all other strings:

public sealed class ItemTemplateSelector : DataTemplateSelector
{
    /// <summary>
    /// This property is set in XAML.
    /// </summary>
    public DataTemplate NormalTemplate { get; set; }

    /// <summary>
    /// This property is set in XAML.
    /// </summary>
    public DataTemplate ThreeTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        if ("Three".Equals(item))
        {
            return ThreeTemplate;
        }

        return NormalTemplate;
    }

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

The data template selector has two versions of SelectTemplateCore. This page discusses which one to use under what circumstances:

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.

The XAML (which assigns data templates to the selector's two properties) looks like this:

<Grid>
    <Grid.Resources>
        <local:ItemTemplateSelector x:Key="ItemTemplateSelector">
            <local:ItemTemplateSelector.NormalTemplate>
                <DataTemplate>
                    <TextBlock Foreground="Blue" Text="{Binding}" />
                </DataTemplate>
            </local:ItemTemplateSelector.NormalTemplate>
            <local:ItemTemplateSelector.ThreeTemplate>
                <DataTemplate>
                    <TextBlock Foreground="Red" Text="{Binding}" />
                </DataTemplate>
            </local:ItemTemplateSelector.ThreeTemplate>
        </local:ItemTemplateSelector>
    </Grid.Resources>
    <ItemsControl
        VerticalAlignment="Center"
        HorizontalAlignment="Center"
        ItemsSource="{x:Bind ItemsSource, Mode=OneWay}"
        ItemTemplateSelector="{StaticResource ItemTemplateSelector}">
    </ItemsControl>
</Grid>

The result looks like this, with the string "Three" shown in red:

ItemsControl

I hope this is sufficient to put you on the right track.

Comments