1
votes

I have 3 DataTemplate in my Window.Resources, strongly typed to three different classes:

<DataTemplate x:Key="myTemplateA" DataType="{x:Type local:SampleClassA}">
    <Grid>
        <TextBlock Text="{Binding Path=SampleProperty1}"></TextBlock>
        <TextBlock Text="{Binding Path=SampleProperty2}"></TextBlock>
        <TextBlock Text="{Binding Path=SamplePropertyA}"></TextBlock>
    </Grid>
</DataTemplate>

<DataTemplate x:Key="myTemplateB" DataType="{x:Type local:SampleClassB}">
    <Grid>
        <TextBlock Text="{Binding Path=SampleProperty1}"></TextBlock>
            <TextBlock Text="{Binding Path=SampleProperty2}"></TextBlock>
            <TextBlock Text="{Binding Path=SamplePropertyB}"></TextBlock>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="myTemplateBase" DataType="{x:Type local:SampleClass}">
        <Grid>
            <TextBlock Text="{Binding Path=SampleProperty1}"></TextBlock>
            <TextBlock Text="{Binding Path=SampleProperty2}"></TextBlock>
        </Grid>
    </DataTemplate>

And a little DataTemplateSelector:

<local:SampleDataTemplateSelector x:Key="myBindPropertyTemplateSelector"
    TemplateA="{StaticResource myTemplateA}"
    TemplateB="{StaticResource myTemplateB}" 
    SampleClassBaseTemplate="{StaticResource myTemplateBase}" />

Obviously there is the class for DataTemplateSelector, called SampleDataTemplateSelector

Public Class SampleDataTemplateSelector
    Inherits DataTemplateSelector

    Public Property TemplateA As DataTemplate
    Public Property TemplateB As DataTemplate
    Public Property SampleClassBaseTemplate As DataTemplate

    Public Overrides Function SelectTemplate(item As Object, container As DependencyObject) As DataTemplate

        If item Is Nothing Then Return SampleClassBaseTemplate

        If item.GetType.Equals(GetType(SampleClassA)) Then
            Return TemplateA
        End If

        If item.GetType.Equals(GetType(SampleClassB)) Then
            Return TemplateB
        End If

        Return SampleClassBaseTemplate
    End Function

End Class

DataTemplateSelector must discriminate 3 simply classes: SampleClass and 2 derived classes SampleClassA, SampleClassB.

Public Class SampleClass
    Public Property SampleProperty1 As String = "Class SampleClass Property1"
    Public Property SampleProperty2 As String = "Class SampleClass Property2"
End Class

Public Class SampleClassA
    Inherits SampleClass
    Public Property SamplePropertyA As String = "Class SampleClassA"
End Class

Public Class SampleClassB
    Inherits SampleClass
    Public Property SamplePropertyB As String = "Class SampleClassB"
End Class

In my window xaml the ContentControl is set like follow:

<ContentControl Content="{Binding BindProperty}" ContentTemplateSelector="{StaticResource myBindPropertyTemplateSelector}" />

Where BindProperty is a property defined on window code behind:

Dim myBindProperty As SampleClass
Public ReadOnly Property BindProperty As SampleClass
    Get
        Return myBindProperty
    End Get
End Property

After all, in my window Load event there is the BindProperty initialization

Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
    myBindProperty = New SampleClassA()
End Sub

There's no compile errors. In execution, the item argument on SampleDataTemplateSelector's SelectTemplate routine is ever Nothing, so it can't choose the right template... and shows nothing. What I am doing wrong?

1
Are you setting the DataContext somewhere? In C#, something like: this.DataContext = this;J.H.
I tryied to set DataContext in the xaml (DataContext="{Binding local:BindProperty}") and also in the code behind (myContentControl.DataContext = myBindProperty), but nothing change.Erminio Ottone
Try, myContentControl.DataContext = this (the window). myBindProperty is not a property so I don't think you can use it (it has to be a property not a member variable). If you set myContentControl.DataContext = BindProperty, then you'd need to change the xaml to Content="{Binding}" because the context would be BindProperty already.J.H.
I tryied myContentControl.DataContext = Me in the Load event, nope, nothing change.Erminio Ottone

1 Answers

4
votes

I recreated your project and it does work if you add DataContext = Me to Window_Loaded. I changed your templates to use a StackPanel instead of a Grid (so the text blocks didn't overlap each other). Here is a complete, working version:

enter image description here

MainWindow.xaml

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication20"
    Loaded="Window_Loaded"
    Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="myTemplateA" DataType="{x:Type local:SampleClassA}">
            <StackPanel>
                <TextBlock Text="{Binding Path=SampleProperty1}"></TextBlock>
                <TextBlock Text="{Binding Path=SampleProperty2}"></TextBlock>
                <TextBlock Text="{Binding Path=SamplePropertyA}"></TextBlock>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="myTemplateB" DataType="{x:Type local:SampleClassB}">
            <StackPanel>
                <TextBlock Text="{Binding Path=SampleProperty1}"></TextBlock>
                <TextBlock Text="{Binding Path=SampleProperty2}"></TextBlock>
                <TextBlock Text="{Binding Path=SamplePropertyB}"></TextBlock>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="myTemplateBase" DataType="{x:Type local:SampleClass}">
            <StackPanel>
                <TextBlock Text="{Binding Path=SampleProperty1}"></TextBlock>
                <TextBlock Text="{Binding Path=SampleProperty2}"></TextBlock>
            </StackPanel>
        </DataTemplate>

        <local:SampleDataTemplateSelector x:Key="myBindPropertyTemplateSelector"
            TemplateA="{StaticResource myTemplateA}"
            TemplateB="{StaticResource myTemplateB}" 
            SampleClassBaseTemplate="{StaticResource myTemplateBase}" />
    </Window.Resources>
    <Grid>
        <ContentControl Content="{Binding BindProperty}" ContentTemplateSelector="{StaticResource myBindPropertyTemplateSelector}" />
    </Grid>
</Window>

MainWindow.xaml.vb

Class MainWindow 
    Dim myBindProperty As SampleClass
    Public ReadOnly Property BindProperty As SampleClass
        Get
            Return myBindProperty
        End Get
    End Property

    Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
        myBindProperty = New SampleClassA()
        DataContext = Me
    End Sub
End Class

Public Class SampleClass
    Public Property SampleProperty1 As String = "Class SampleClass Property1"
    Public Property SampleProperty2 As String = "Class SampleClass Property2"
End Class

Public Class SampleClassA
    Inherits SampleClass
    Public Property SamplePropertyA As String = "Class SampleClassA"
End Class

Public Class SampleClassB
    Inherits SampleClass
    Public Property SamplePropertyB As String = "Class SampleClassB"
End Class

Public Class SampleDataTemplateSelector
    Inherits DataTemplateSelector

    Public Property TemplateA As DataTemplate
    Public Property TemplateB As DataTemplate
    Public Property SampleClassBaseTemplate As DataTemplate

    Public Overrides Function SelectTemplate(item As Object, container As DependencyObject) As DataTemplate

        If item Is Nothing Then Return SampleClassBaseTemplate

        If item.GetType.Equals(GetType(SampleClassA)) Then
            Return TemplateA
        End If

        If item.GetType.Equals(GetType(SampleClassB)) Then
            Return TemplateB
        End If

        Return SampleClassBaseTemplate
    End Function

End Class