Silverlight ContentPresenter正在丢失数据上下文

Silverlight ContentPresenter正在丢失数据上下文,silverlight,silverlight-2.0,Silverlight,Silverlight 2.0,我想创建一个“FlipPanel”,它提供同一对象的两个不同视图。这是我正在采取的方法 这是主页面,由ItemsControl组成,其ItemTemplate是FlipPanel。FlipPanel公开了两个属性,它们定义了用于正面和背面的DataTemplate <UserControl.Resources> <ControlTemplate x:Key="MyFlipTemplate"> <StackPanel>

我想创建一个“FlipPanel”,它提供同一对象的两个不同视图。这是我正在采取的方法

这是主页面,由ItemsControl组成,其ItemTemplate是FlipPanel。FlipPanel公开了两个属性,它们定义了用于正面和背面的DataTemplate

<UserControl.Resources>

    <ControlTemplate x:Key="MyFlipTemplate">
        <StackPanel>
            <Button Content="Flip" x:Name="PART_FlipButton"/>
            <ContentPresenter Content="{TemplateBinding Content}" x:Name="PART_FlipContent"/>
        </StackPanel>
    </ControlTemplate>

    <DataTemplate x:Key="Front">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Front"/>
            <TextBlock Text="{Binding Name}"/>
        </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="Back">
        <StackPanel>
            <TextBlock Text="Back"/>
            <TextBlock Text="{Binding Description}"/>
        </StackPanel>
    </DataTemplate>
</UserControl.Resources>

<StackPanel>
    <ItemsControl x:Name="_items">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <SLTest:FlipPanel Template="{StaticResource MyFlipTemplate}" FrontDataTemplate="{StaticResource Front}" BackDataTemplate="{StaticResource Back}" Side="Front"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>


主页背后的代码非常简单,因为它只是将ItemsControl的DataContext设置为测试数据列表

using System.Collections.Generic; using System.Windows.Controls; namespace SLTest { public partial class NewPage : UserControl { public NewPage() { InitializeComponent(); _items.ItemsSource = Items; } public IList Items { get { return new List { new NewClass { Name = "Name 1", Description = "Description 1"}, new NewClass { Name = "Name 2", Description = "Description 2"}, new NewClass { Name = "Name 3", Description = "Description 3"}, new NewClass { Name = "Name 4", Description = "Description 4"} }; } } } public class NewClass { public string Name; public string Description; } } 使用System.Collections.Generic; 使用System.Windows.Controls; 名称空间SLTest { 公共部分类NewPage:UserControl { 公共新页() { 初始化组件(); _items.ItemsSource=项目; } 公共物品 { 得到 { 返回新列表 { 新建类{Name=“Name 1”,Description=“Description 1”}, 新建类{Name=“Name 2”,Description=“Description 2”}, 新建类{Name=“Name 3”,Description=“Description 3”}, 新建类{Name=“Name 4”,Description=“Description 4”} }; } } } 公共类新类 { 公共字符串名称; 公共字符串描述; } } FlipPanel代码也相对简单,因为它试图基于Side dependencProperty更改数据模板。问题似乎是ContentPresenter的DataContext在某个时候丢失了。在代码中,我有两条注释指示ContentPresenter的DataContext的有效性

using System; using System.Windows; using System.Windows.Controls; namespace SLTest { [TemplatePart(Name = FlipPanel.ButtonPart, Type = typeof(Button))] [TemplatePart(Name = FlipPanel.ContentPart, Type = typeof(ContentPresenter))] public partial class FlipPanel : ContentControl { private const string ButtonPart = "PART_FlipButton"; private const string ContentPart = "PART_FlipContent"; public enum FlipSide { Front, Back } private FlipSide _flipSide; public static readonly DependencyProperty SideProperty = DependencyProperty.RegisterAttached("FlipSide", typeof(FlipSide), typeof(FlipPanel), new PropertyMetadata(FlipSide.Front, FlipSidePropertyChanged)); public static readonly DependencyProperty FrontDataTemplateProperty = DependencyProperty.Register("FrontDataTemplate", typeof (DataTemplate), typeof (FlipPanel), null); public static readonly DependencyProperty BackDataTemplateProperty = DependencyProperty.Register("BackDataTemplate", typeof(DataTemplate), typeof(FlipPanel), null); private Button _flipButton; private ContentPresenter _content; public FlipPanel() { InitializeComponent(); } public DataTemplate FrontDataTemplate { get { return (DataTemplate) GetValue(FrontDataTemplateProperty); } set { SetValue(FrontDataTemplateProperty, value); } } public DataTemplate BackDataTemplate { get { return (DataTemplate)GetValue(BackDataTemplateProperty); } set { SetValue(BackDataTemplateProperty, value); } } private static void FlipSidePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var flipSide = (FlipSide)e.NewValue; var flipPanel = d as FlipPanel; flipPanel._content.ContentTemplate = flipSide == FlipSide.Front ? flipPanel.FrontDataTemplate : flipPanel.BackDataTemplate; } public override void OnApplyTemplate() { _flipButton = GetTemplateChild(ButtonPart) as Button; _flipButton.Click += OnFlipClicked; _content = GetTemplateChild(ContentPart) as ContentPresenter; // _content.DataContext is valid right here... _content.ContentTemplate = Side == FlipSide.Front ? FrontDataTemplate : BackDataTemplate; base.OnApplyTemplate(); } private void OnFlipClicked(object sender, RoutedEventArgs e) { // _content.DataContext is now NULL!!!! Side = (Side == FlipSide.Front) ? FlipSide.Back : FlipSide.Front; } public FlipSide Side { get { return (FlipSide) GetValue(SideProperty); } set { SetValue(SideProperty, value); } } } } 使用制度; 使用System.Windows; 使用System.Windows.Controls; 名称空间SLTest { [TemplatePart(名称=FlipPanel.ButtonPart,类型=类型(按钮))] [TemplatePart(Name=FlipPanel.ContentPart,Type=typeof(ContentPresenter))] 公共部分类FlipPanel:ContentControl { private const string ButtonPart=“PART\u FlipButton”; 私有常量字符串ContentPart=“PART\u FlipContent”; 公共枚举反面 { 前面,, 返回 } 私人FlipSide _FlipSide; public static readonly dependencProperty SideProperty=dependencProperty.RegisterAttached(“FlipSide”、typeof(FlipSide)、typeof(FlipPanel)、new PropertyMetadata(FlipSide.Front、FlipSidePropertyChanged)); 公共静态只读DependencyProperty FrontDataTemplateProperty=DependencyProperty.Register(“FrontDataTemplate”、typeof(DataTemplate)、typeof(FlipPanel)、null); public static readonly dependencProperty BackDataTemplateProperty=dependencProperty.Register(“BackDataTemplate”、typeof(DataTemplate)、typeof(FlipPanel)、null); 私人按钮_flipButton; 私有内容展示者(content presenter)内容;; 公共FlipPanel() { 初始化组件(); } 公共数据模板FrontDataTemplate { 得到 { 返回(DataTemplate)GetValue(FrontDataTemplateProperty); } 设置 { SetValue(FrontDataTemplateProperty,值); } } 公共数据模板BackDataTemplate { 得到 { 返回(DataTemplate)GetValue(BackDataTemplateProperty); } 设置 { SetValue(BackDataTemplateProperty,值); } } 私有静态void FlipSidePropertyChanged(DependencyObject d、DependencyPropertyChangedEventArgs e) { var flipSide=(flipSide)e.NewValue; var flipPanel=d作为flipPanel; flipPanel.\u content.ContentTemplate=flipSide==flipSide.Front?flipPanel.FrontDataTemplate:flipPanel.BackDataTemplate; } 应用程序模板()上的公共重写无效 { _flipButton=GetTemplateChild(ButtonPart)作为按钮; _flipButton.Click+=OnFlipClicked; _content=GetTemplateChild(ContentPart)作为ContentPresenter; //\u content.DataContext在此处有效。。。 _content.ContentTemplate=Side==FlipSide.Front?FrontDataTemplate:BackDataTemplate; base.OnApplyTemplate(); } FlipClicked上的私有void(对象发送方、路由目标方) { //\u content.DataContext现在为空!!!! 侧面=(侧面==反面。正面)?反面。背面:反面。正面; } 公共反面 { 得到 { 返回(FlipSide)GetValue(SideProperty); } 设置 { SetValue(SideProperty,value); } } } } 有什么想法吗

我不确定这是否是解决我的需求的正确方法,如果有更好的方法,我欢迎任何进一步的建议

谢谢你,克里斯

我不知道你是否还在想办法。我知道有很多类似问题的指南,但并不完全是你想要的。根据我对您的理解,您需要一个具有两个面(实际上是x面)的控件,用户可以按下按钮,使面板“翻转”并显示不同的数据。但是,您希望显示的数据足够通用,以便此翻转面板可以在其他位置使用不同的实现,而不是完全不同的代码。我是否正确理解您的需求?如果没有,请说明在哪里
    <Grid x:Name="LayoutRoot" Background="White">
  <controls:FlipPanel x:Name="TestingFlipPanel" Side="Front" >
   <controls:FlipPanel.BackDataTemplate>
    <DataTemplate>
     <StackPanel Orientation="Horizontal">
      <TextBlock Text="Back: "/>
      <TextBlock Text="{Binding BackText}" />
     </StackPanel>
    </DataTemplate>
   </controls:FlipPanel.BackDataTemplate>
   <controls:FlipPanel.FrontDataTemplate>
    <DataTemplate>
     <StackPanel Orientation="Horizontal">
      <TextBlock Text="Front: "/>
      <TextBlock Text="{Binding FrontText}" />
     </StackPanel>
    </DataTemplate>
   </controls:FlipPanel.FrontDataTemplate>
  </controls:FlipPanel>
    </Grid>
Public Class BindingObject
 Private _FrontText As String
 Private _BackText As String

 Public Sub New(ByVal frontText As String, ByVal backText As String)
  MyBase.New()
  _FrontText = frontText
  _BackText = backText
 End Sub

 Public Property FrontText() As String
  Get
   Return _FrontText
  End Get
  Set(ByVal value As String)
   _FrontText = value
  End Set
 End Property
 Public Property BackText() As String
  Get
   Return _BackText
  End Get
  Set(ByVal value As String)
   _BackText = value
  End Set
 End Property

End Class
Partial Public Class Page
 Inherits UserControl
 Dim _BindingObject As New BindingObject("This is the front", "This is the back")
 Public Sub New()
  InitializeComponent()
 End Sub

 Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
  TestingFlipPanel.DataContext = _BindingObject
 End Sub
End Class
    <Style TargetType="controls:FlipPanel">
  <Setter Property="Template">
   <Setter.Value>
    <ControlTemplate TargetType="controls:FlipPanel">
     <Grid x:Name="LayoutRoot">
      <Grid>
       <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
       </Grid.RowDefinitions>
       <Button x:Name="FlipButton" Content="Flip" Grid.Row="0" />
       <ContentPresenter Grid.Row="1" x:Name="FrontContentPresenter" Content="{TemplateBinding DataContext}" ContentTemplate="{TemplateBinding FrontDataTemplate}" />
       <ContentPresenter Grid.Row="1" x:Name="BackContentPresenter"  Content="{TemplateBinding DataContext}" ContentTemplate="{TemplateBinding BackDataTemplate}" />
      </Grid>

     </Grid>
    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>
<TemplatePart(Name:=FlipPanel.LayoutRoot_ElementName, Type:=GetType(FrameworkElement))> _
<TemplatePart(Name:=FlipPanel.FrontContentPresenter_ElementName, Type:=GetType(FrameworkElement))> _
<TemplatePart(Name:=FlipPanel.BackContentPresenter_ElementName, Type:=GetType(FrameworkElement))> _
<TemplatePart(Name:=FlipPanel.FlipButton_ElementName, Type:=GetType(FrameworkElement))> _
Public Class FlipPanel
 Inherits Control

 Public Const LayoutRoot_ElementName As String = "LayoutRoot"
 Public Const FlipButton_ElementName As String = "FlipButton"
 Public Const FrontContentPresenter_ElementName As String = "FrontContentPresenter"
 Public Const BackContentPresenter_ElementName As String = "BackContentPresenter"

 Public Enum Sides
  Front
  Back
 End Enum

 Private _LayoutRoot As FrameworkElement = Nothing
 Private _FlipButton As FrameworkElement = Nothing
 Private _FrontContentPresenter As FrameworkElement = Nothing
 Private _BackContentPresenter As FrameworkElement = Nothing

 Private _ControlUpdating As Boolean = False

 Public Sub New()
  MyBase.New()
  MyBase.DefaultStyleKey = GetType(FlipPanel)
 End Sub

 Public Overrides Sub OnApplyTemplate()
  MyBase.OnApplyTemplate()
  UpdateControl()
 End Sub

 Private Sub UpdateControl()
  If _ControlUpdating Then Exit Sub
  _ControlUpdating = True

  If _LayoutRoot Is Nothing Then _LayoutRoot = TryCast(GetTemplateChild(LayoutRoot_ElementName), FrameworkElement)
  If _LayoutRoot IsNot Nothing Then
   Dim element As Grid = TryCast(_LayoutRoot, Grid)
   If element IsNot Nothing Then
    ' Update LayoutGrid here.  
   End If
  End If
  If _FlipButton Is Nothing Then _FlipButton = TryCast(GetTemplateChild(FlipButton_ElementName), FrameworkElement)
  If _FlipButton IsNot Nothing Then
   Dim element As Button = TryCast(_FlipButton, Button)
   If element IsNot Nothing Then
    ' Update Button
    RemoveHandler element.Click, AddressOf _FlipButton_Click
    AddHandler element.Click, AddressOf _FlipButton_Click
   End If
  End If
  If _FrontContentPresenter Is Nothing Then _FrontContentPresenter = TryCast(GetTemplateChild(FrontContentPresenter_ElementName), FrameworkElement)
  If _FrontContentPresenter IsNot Nothing Then
   Dim element As ContentPresenter = TryCast(_FrontContentPresenter, ContentPresenter)
   If element IsNot Nothing Then
    ' Update FrontContentPresenter here.
    If Side = Sides.Front Then
     element.Visibility = Windows.Visibility.Visible
    Else
     element.Visibility = Windows.Visibility.Collapsed
    End If
   End If
  End If
  If _BackContentPresenter Is Nothing Then _BackContentPresenter = TryCast(GetTemplateChild(BackContentPresenter_ElementName), FrameworkElement)
  If _BackContentPresenter IsNot Nothing Then
   Dim element As ContentPresenter = TryCast(_BackContentPresenter, ContentPresenter)
   If element IsNot Nothing Then
    ' Update BackContentPresenter here.  
    If Side = Sides.Front Then
     element.Visibility = Windows.Visibility.Collapsed
    Else
     element.Visibility = Windows.Visibility.Visible
    End If
   End If
  End If


  _ControlUpdating = False
 End Sub

 Private Sub _FlipButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
  Select Case Side
   Case Sides.Front
    Side = Sides.Back
   Case Sides.Back
    Side = Sides.Front
   Case Else
    Throw New ArgumentOutOfRangeException("Side")
  End Select
  UpdateControl()
 End Sub

 Private Sub FlipPanel_LayoutUpdated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.LayoutUpdated
  UpdateControl()
 End Sub

#Region " FrontDataTemplateProperty Dependency Property "

#Region " FrontDataTemplate Property "

 Public Property FrontDataTemplate() As DataTemplate
  Get
   Return DirectCast(GetValue(FrontDataTemplateProperty), DataTemplate)
  End Get
  Set(ByVal value As DataTemplate)
   SetValue(FrontDataTemplateProperty, value)
  End Set
 End Property

#End Region

#Region " FrontDataTemplate Dependency Property "

 Public Shared ReadOnly FrontDataTemplateProperty As DependencyProperty = DependencyProperty.Register("FrontDataTemplate", GetType(DataTemplate), GetType(FlipPanel), New PropertyMetadata(Nothing, AddressOf OnFrontDataTemplatePropertyChanged))

#End Region

#Region " FrontDataTemplate Property Changed CallBack "

 Private Shared Sub OnFrontDataTemplatePropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
  If e.OldValue Is Nothing AndAlso e.NewValue Is Nothing Then Exit Sub
  If e.OldValue IsNot Nothing AndAlso e.OldValue.Equals(e.NewValue) Then Exit Sub

  Dim source As FlipPanel = TryCast(d, FlipPanel)
  If source Is Nothing Then Throw New ArgumentException("source is not an instance of FlipPanel!")

  ' Provide any other validation here.

  ' Apply any other changes here.

 End Sub

#End Region

#End Region

#Region " BackDataTemplateProperty Dependency Property "

#Region " BackDataTemplate Property "

 Public Property BackDataTemplate() As DataTemplate
  Get
   Return DirectCast(GetValue(BackDataTemplateProperty), DataTemplate)
  End Get
  Set(ByVal value As DataTemplate)
   SetValue(BackDataTemplateProperty, value)
  End Set
 End Property

#End Region

#Region " BackDataTemplate Dependency Property "

 Public Shared ReadOnly BackDataTemplateProperty As DependencyProperty = DependencyProperty.Register("BackDataTemplate", GetType(DataTemplate), GetType(FlipPanel), New PropertyMetadata(Nothing, AddressOf OnBackDataTemplatePropertyChanged))

#End Region

#Region " BackDataTemplate Property Changed CallBack "

 Private Shared Sub OnBackDataTemplatePropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
  If e.OldValue Is Nothing AndAlso e.NewValue Is Nothing Then Exit Sub
  If e.OldValue IsNot Nothing AndAlso e.OldValue.Equals(e.NewValue) Then Exit Sub

  Dim source As FlipPanel = TryCast(d, FlipPanel)
  If source Is Nothing Then Throw New ArgumentException("source is not an instance of FlipPanel!")

  ' Provide any other validation here.

  ' Apply any other changes here.

 End Sub

#End Region

#End Region

#Region " SideProperty Dependency Property "

#Region " Side Property "

 Public Property Side() As Sides
  Get
   Return DirectCast(GetValue(SideProperty), Sides)
  End Get
  Set(ByVal value As Sides)
   SetValue(SideProperty, value)
  End Set
 End Property

#End Region

#Region " Side Dependency Property "

 Public Shared ReadOnly SideProperty As DependencyProperty = DependencyProperty.Register("Side", GetType(Sides), GetType(FlipPanel), New PropertyMetadata(Sides.Front, AddressOf OnSidePropertyChanged))

#End Region

#Region " Side Property Changed CallBack "

 Private Shared Sub OnSidePropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
  If e.OldValue Is Nothing AndAlso e.NewValue Is Nothing Then Exit Sub
  If e.OldValue IsNot Nothing AndAlso e.OldValue.Equals(e.NewValue) Then Exit Sub

  Dim source As FlipPanel = TryCast(d, FlipPanel)
  If source Is Nothing Then Throw New ArgumentException("source is not an instance of FlipPanel!")

  ' Provide any other validation here.

  ' Apply any other changes here.

 End Sub

#End Region

#End Region

End Class