Silverlight Defaulting ContentPresenter Content

1.4k views Asked by At

Why won't this work?

In generic.xaml for a custom control:

In the style applied to the custom control...

<Setter Property="ChromeContent">
  <Setter.Value>
    <Grid />
  </Setter.Value>
</Setter>

...

Later, in the control template...

<ContentPresenter Grid.Column="0" 
     x:Name="ChromeContentPresenter" 
     Content="{TemplateBinding ChromeContent}" />

Here's the dependency property for ChromeContent...

public Object ChromeContent
{
  get { return (Object)GetValue(ChromeContentProperty); }
  set { SetValue(ChromeContentProperty, value); }
}
public static readonly DependencyProperty ChromeContentProperty =
    DependencyProperty.Register("ChromeContent", typeof(Object), 
    typeof(casPopup), null);

As you can see, it takes any object. I tried changing it to a Grid, but that did not help.

It throws this error (from javascript): _Failed to assign to property 'System.Windows.Controls.ContentPresenter.Content'

Oddly, the following will work fine if I remove the Grid from the setter nd just use text:

<Setter Property="ChromeContent" Value="DEFAULT" />

Also, this will work too from the OnApplyTemplate method in the control class:

  Grid g = new Grid();
  g.Width = 100;
  g.Height = 25;
  g.Background = new SolidColorBrush(Colors.LightGray);
  ChromeContent = g;

I'm having a hard time understanding what is preventing the default content of a grid, defined in the generic.xaml from working. Does anyone have any knowledge on this matter?

Many thanks in advance for your help!

1

There are 1 answers

1
AnthonyWJones On BEST ANSWER

This is the problem:-

<Setter Property="ChromeContent">
  <Setter.Value>
    <Grid />
  </Setter.Value>
</Setter>

You should not include a UIElement directly in a resource dictionary or as a value of a style. You might see the style as being some kind of descriptor but it isn't. The values in a style are constructed instances of the objects they hold. Your style holds a single instance of Grid. Whenever that style is used to assign to a ChromeContent property it will attempt to assing the same single instance of the Grid.

A UIElement can only be a child of one parent. What would happen if two instances your control were constructed? There would (if silverlight let you) be an attempt to assign the same single instance of the Grid to both controls.

This is one reason for templates such as ControlTemplate and DataTemplate. The markup inside these is invoked each time the template is used rather than when the Xaml is first parsed.

Edit:

To answer you supplementary question, you should default another property of type DataTemplate:-

<Setter Property="ChromeContentTemplate">
  <Setter.Value>
    <DataTemplate>
      <Grid />
    </DataTemplate>
  </Setter.Value>
</Setter>

Property:-

public Object ChromeContentTemplate
{
  get { return (DataTemplate)GetValue(ChromeContentTemplateProperty); }
  set { SetValue(ChromeContentTemplateProperty, value); }
}

public static readonly DependencyProperty ChromeContentTemplateProperty=
    DependencyProperty.Register("ChromeContentTemplate", typeof(DataTemplate), 
    typeof(casPopup), null);

Control Template:-

<ContentPresenter Grid.Column="0" 
     x:Name="ChromeContentPresenter" 
     Content="{TemplateBinding ChromeContent}"
     ContentTemplate="{TemplateBinding ChromeContentTemplate" />