Note that there are some explanatory texts on larger screens.

plurals
  1. POContentPresenter losing DataContext
    primarykey
    data
    text
    <p>I want to create a "FlipPanel", which provides two different views of the same object. Here is the approach I am taking.</p> <p>This is the main page, which consists of an ItemsControl whose ItemTemplate is a FlipPanel. The FlipPanel exposes two properties which define the DataTemplate to use for the Front and the Back.</p> <p></p> <pre><code>&lt;UserControl.Resources&gt; &lt;ControlTemplate x:Key="MyFlipTemplate"&gt; &lt;StackPanel&gt; &lt;Button Content="Flip" x:Name="PART_FlipButton"/&gt; &lt;ContentPresenter Content="{TemplateBinding Content}" x:Name="PART_FlipContent"/&gt; &lt;/StackPanel&gt; &lt;/ControlTemplate&gt; &lt;DataTemplate x:Key="Front"&gt; &lt;StackPanel Orientation="Horizontal"&gt; &lt;TextBlock Text="Front"/&gt; &lt;TextBlock Text="{Binding Name}"/&gt; &lt;/StackPanel&gt; &lt;/DataTemplate&gt; &lt;DataTemplate x:Key="Back"&gt; &lt;StackPanel&gt; &lt;TextBlock Text="Back"/&gt; &lt;TextBlock Text="{Binding Description}"/&gt; &lt;/StackPanel&gt; &lt;/DataTemplate&gt; &lt;/UserControl.Resources&gt; &lt;StackPanel&gt; &lt;ItemsControl x:Name="_items"&gt; &lt;ItemsControl.ItemsPanel&gt; &lt;ItemsPanelTemplate&gt; &lt;StackPanel&gt;&lt;/StackPanel&gt; &lt;/ItemsPanelTemplate&gt; &lt;/ItemsControl.ItemsPanel&gt; &lt;ItemsControl.ItemTemplate&gt; &lt;DataTemplate&gt; &lt;SLTest:FlipPanel Template="{StaticResource MyFlipTemplate}" FrontDataTemplate="{StaticResource Front}" BackDataTemplate="{StaticResource Back}" Side="Front"/&gt; &lt;/DataTemplate&gt; &lt;/ItemsControl.ItemTemplate&gt; &lt;/ItemsControl&gt; &lt;/StackPanel&gt; </code></pre> <p></p> <p>The Code Behind for the main page, is very simple as it just sets the DataContext of the ItemsControl to a list of Test Data.</p> <pre> 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; } } </pre> <p>The FlipPanel code is relatively simple as well, as it attempts to change the DataTemplate based on the Side DependencyProperty. The issue appears to be that the ContentPresenter's DataContext is lost at some point. In the code I have two comments that indicate the validity of the DataContext for the ContentPresenter.</p> <pre> 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); } } } } </pre> <p>Any ideas?</p> <p>I am not sure if this is the right approach to solving my requirement, if there is a better way I would welcome any further suggestions.</p> <p>Thanks</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload