【问题标题】:Binding a DataTemplate to ContentControl with ContentTemplateSelector使用 ContentTemplateSelector 将 DataTemplate 绑定到 ContentControl
【发布时间】:2014-11-04 10:03:21
【问题描述】:

我的 Window.Resources 中有 3 个 DataTemplate,强类型为三个不同的类:

<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>

还有一点 DataTemplateSelector:

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

显然有DataTemplateSelector的类,叫做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 必须区分 3 个简单的类:SampleClass 和 2 个派生类 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

在我的窗口 xaml 中,ContentControl 设置如下:

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

其中 BindProperty 是定义在窗口代码后面的属性:

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

毕竟,在我的窗口加载事件中有 BindProperty 初始化

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

没有编译错误。在执行过程中,SampleDataTemplateSelector 的 SelectTemplate 例程上的 item 参数永远是 Nothing,因此它无法选择正确的模板......并且什么也不显示。我做错了什么?

【问题讨论】:

  • 您是否在某处设置了 DataContext?在 C# 中,类似于:this.DataContext = this;
  • 我尝试在 xaml (DataContext="{Binding local:BindProperty}") 和后面的代码 (myContentControl.DataContext = myBindProperty) 中设置 DataContext,但没有任何改变。
  • 试试,myContentControl.DataContext = this(窗口)。 myBindProperty 不是属性,所以我认为您不能使用它(它必须是属性而不是成员变量)。如果您设置 myContentControl.DataContext = BindProperty,那么您需要将 xaml 更改为 Content="{Binding}" 因为上下文已经是 BindProperty。
  • 我在 Load 事件中尝试了 myContentControl.DataContext = Me,不,没有任何变化。

标签: wpf data-binding binding datatemplate contentcontrol


【解决方案1】:

我重新创建了您的项目,如果您将 DataContext = Me 添加到 Window_Loaded,它确实可以工作。我将您的模板更改为使用 StackPanel 而不是 Grid(因此文本块不会相互重叠)。 这是一个完整的工作版本:

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

【讨论】:

  • 嗨,谢谢你的回答,JH...我不明白,代码是一样的...唯一的区别在于命名空间:xmlns:local="clr-namespace:Cacatua ;assembly=" 我所有的项目文件都在“Cacatua”命名空间中,并且在同一个程序集中。我的程序集没有根命名空间。
  • 奇怪的是调试:如果我在 SelectTemplate 中放置一个断点,Item 什么都不是,因为它在初始化 myBindProperty 的 Window_Loaded 事件之前调用 DataTemplateSelector。在 InitializeComponent 调用之前,我尝试在构造函数上初始化 BindProperty,但 SelectTemplate 中的项目永远是 Nothing(所以我什么都看不到)。
  • 好吧,我的错,代码工作!谢谢J.H.!如果你来意大利,我会请你喝一杯!非常感谢!!!
猜你喜欢
  • 1970-01-01
  • 2016-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
相关资源
最近更新 更多