1
ļ»æ// Copyright Ā© Microsoft Corporation.
2
// This source is subject to the Microsoft Source License for Silverlight Controls (March 2008 Release).
3
// Please see http://go.microsoft.com/fwlink/?LinkID=111693 for details.
4
// All other rights reserved.
7
using System.ComponentModel;
8
using System.Diagnostics;
9
using System.Windows.Documents;
10
using System.Windows.Markup;
11
using System.Windows.Media;
12
using System.Windows.Controls;
14
namespace System.Windows.Controls
17
/// Displays the content of a ContentControl.
20
/// Typically, you the ContentPresenter directly within the ControlTemplate
21
/// of a ContentControl to mark where the content should be displayed.
22
/// Every type derived from ContentControl should have a ContentPrenter in
23
/// its ControlTemplate (although it may not necessarily be a TemplatePart).
24
/// The ContentPresenter in the ControlTemplate should use a TemplateBinding
25
/// to associate ContentControl.Content with ContentPresenter.Content (and
26
/// an other relevant properties like FontSize, VeriticalAlignment, etc.).
28
public class ContentPresenter : Control
31
/// XAML markup used to define the write-once ContentPresenter template.
33
private const string ContentPresenterDefaultTemplate =
35
"xmlns=\"http://schemas.microsoft.com/client/2007\" " +
36
"xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" " +
37
"xmlns:controls=\"clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls\" " +
38
"TargetType=\"controls:ContentPresenter\">" +
39
"<Grid x:Name=\"RootElement\" " +
40
"Background=\"{TemplateBinding Background}\" " +
41
"Cursor=\"{TemplateBinding Cursor}\">" +
42
"<TextBlock x:Name=\"TextElement\" " +
43
"FontFamily=\"{TemplateBinding FontFamily}\" " +
44
"FontSize=\"{TemplateBinding FontSize}\" " +
45
"FontStretch=\"{TemplateBinding FontStretch}\" " +
46
"FontStyle=\"{TemplateBinding FontStyle}\" " +
47
"FontWeight=\"{TemplateBinding FontWeight}\" " +
48
"Foreground=\"{TemplateBinding Foreground}\" " +
49
"HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" " +
50
"Padding=\"{TemplateBinding Padding}\" " +
51
"TextAlignment=\"{TemplateBinding TextAlignment}\" " +
52
"TextDecorations=\"{TemplateBinding TextDecorations}\" " +
53
"TextWrapping=\"{TemplateBinding TextWrapping}\" " +
54
"VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\" " +
55
"Visibility=\"Collapsed\" />" +
60
/// Root element of the panel that will contain the visual content.
63
/// Since a Control cannot change its content (i.e. it may only call
64
/// InitializeFromXaml once to set its root), every ContentPresetner
65
/// will create a container as its root element regardless of the
66
/// content that will be stuffed into it. It's also worth noting that
67
/// there is no TemplatePartAttribute because the Template is write-once
68
/// and cannot be changed by users. This field is marked internal for
71
internal Grid _elementRoot;
72
internal const string RootElementName = "RootElement";
75
/// Visual representation of the Content currently being displayed.
77
/// <remarks>This field is marked internal for unit testing.</remarks>
78
internal UIElement _elementContent;
81
/// Visual representation of any text Content currently being displayed.
84
/// The _elementText property is necessary in addition to the
85
/// _elementContent property because of all of all the font related
86
/// properties whose values need to be propogated into it by the
87
/// ContentPresenter. This field is marked internal for unit testing.
89
internal TextBlock _elementText;
90
internal const string ElementTextContentName = "TextElement";
93
/// True if the template has already been applied, false otherwise.
95
internal bool _alreadyAppliedTemplate;
99
/// Gets or sets the data used to generate the contentPresenter elements of a
100
/// ContentPresenter.
102
public object Content
104
get { return GetValue(ContentProperty); }
105
set { SetValue(ContentProperty, value); }
109
/// Identifies the Content dependency property.
111
public static readonly DependencyProperty ContentProperty =
112
DependencyProperty.Register(
115
typeof(ContentPresenter),
116
new PropertyMetadata(OnContentPropertyChanged));
119
/// ContentProperty property changed handler.
121
/// <param name="d">ContentPresenter that changed its Content.</param>
122
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
123
private static void OnContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
125
ContentPresenter source = d as ContentPresenter;
126
Debug.Assert(source != null,
127
"The source is not an instance of ContentPresenter!");
129
// Use the Content as the DataContext to enable bindings in
131
if (source.ContentTemplate != null)
133
source.DataContext = e.NewValue;
136
// Display the Content
137
source.PrepareContentPresenter();
141
#region ContentTemplate
143
/// Gets or sets the data template used to display the content of the
144
/// ContentPresenter.
146
public DataTemplate ContentTemplate
148
get { return GetValue(ContentTemplateProperty) as DataTemplate; }
149
set { SetValue(ContentTemplateProperty, value); }
153
/// Identifies the ContentTemplate dependency property.
155
public static readonly DependencyProperty ContentTemplateProperty =
156
DependencyProperty.Register(
158
typeof(DataTemplate),
159
typeof(ContentPresenter),
160
new PropertyMetadata(OnContentTemplatePropertyChanged));
163
/// ContentTemplateProperty property changed handler.
165
/// <param name="d">ContentPresenter that changed its ContentTemplate.</param>
166
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
167
private static void OnContentTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
169
ContentPresenter source = d as ContentPresenter;
170
Debug.Assert(source != null,
171
"The source is not an instance of ContentPresenter!");
173
// Use the Content as the DataContext to enable bindings in
174
// ContentTemplate or clear it if we removed our template (NOTE:
175
// this should use ClearValue instead when it's available).
176
source.DataContext = e.NewValue != null ? source.Content : null;
178
// Display the Content
179
source.PrepareContentPresenter();
181
#endregion ContentTemplate
183
#region TextAlignment
185
/// Gets or sets a value that indicates the horizontal alignment of text
188
public TextAlignment TextAlignment
190
get { return (TextAlignment) GetValue(TextAlignmentProperty); }
191
set { SetValue(TextAlignmentProperty, value); }
195
/// Identifies the TextAlignment dependency property.
197
public static readonly DependencyProperty TextAlignmentProperty =
198
DependencyProperty.Register(
200
typeof(TextAlignment),
201
typeof(ContentPresenter),
203
#endregion TextAlignment
205
#region TextDecorations
207
/// Gets or sets a TextDecorationCollection that contains the effects to
208
/// apply to the Content text.
210
[TypeConverter(typeof(TextDecorationCollectionConverter))]
211
public TextDecorationCollection TextDecorations
213
get { return GetValue(TextDecorationsProperty) as TextDecorationCollection; }
214
set { SetValue(TextDecorationsProperty, value); }
218
/// Identifies the TextDecorations dependency property.
220
public static readonly DependencyProperty TextDecorationsProperty =
221
DependencyProperty.Register(
223
typeof(TextDecorationCollection),
224
typeof(ContentPresenter),
226
#endregion TextDecorations
230
/// Gets or sets a value that indicates how the TextBlock should wrap
233
public TextWrapping TextWrapping
235
get { return (TextWrapping) GetValue(TextWrappingProperty); }
236
set { SetValue(TextWrappingProperty, value); }
240
/// Identifies the TextWrapping dependency property.
242
public static readonly DependencyProperty TextWrappingProperty =
243
DependencyProperty.Register(
245
typeof(TextWrapping),
246
typeof(ContentPresenter),
248
#endregion TextWrapping
251
/// Initializes a new instance of the ContentPresenter class.
253
public ContentPresenter()
255
// Apply the default Template to ContentPresenter.
256
Template = XamlReader.Load(ContentPresenterDefaultTemplate) as ControlTemplate;
258
Debug.Assert(_alreadyAppliedTemplate,
259
"The write-once Template flag _alreadyAppliedTemplate was not set!");
263
/// Apply the default Template to ContentPresenter. This is only
264
/// allowed to happen one time.
266
public override void OnApplyTemplate()
268
// Ensure that the Template property is set/applied only once (from
270
if (_alreadyAppliedTemplate)
272
throw new InvalidOperationException(Resource.ContentPresenter_OnApplyTemplate_WriteOnce);
274
_alreadyAppliedTemplate = true;
276
// Get the content root and the text content visual
277
_elementRoot = GetTemplateChild(RootElementName) as Grid;
278
Debug.Assert(_elementRoot != null,
279
"The required template part RootElement was not found!");
281
_elementText = GetTemplateChild(ElementTextContentName) as TextBlock;
282
Debug.Assert(_elementText != null,
283
"The required template part TextElement is not an instance of TextBlock!");
285
// Ensure the template parts were structured correctly
286
Debug.Assert(_elementContent == null,
287
"_elementContent should not exist when applying the template!");
288
Debug.Assert(_elementRoot.Children.Contains(_elementText),
289
"TextElement should be a child of RootElement!");
290
Debug.Assert(_elementRoot.Children.Count == 1,
291
"RootElement should have TextElement as its only child!");
295
/// Update the ContentPresenter's logical tree with the appropriate
296
/// visual elements when its Content is changed.
298
private void PrepareContentPresenter()
300
Debug.Assert(_elementRoot != null, "RootElement is null!");
301
Debug.Assert(_elementText != null, "TextElement is null!");
303
// Remove the old content
304
if (_elementContent != _elementText)
306
_elementRoot.Children.Remove(_elementContent);
307
_elementContent = null;
311
_elementText.Text = null;
314
// Expand the ContentTemplate if it exists
315
DataTemplate template = ContentTemplate;
316
object content = (template != null) ?
317
template.LoadContent() :
320
// Add the new content
321
UIElement element = content as UIElement;
324
_elementContent = element;
325
_elementRoot.Children.Add(_elementContent);
326
_elementText.Visibility = Visibility.Collapsed;
328
else if (content != null)
330
_elementText.Visibility = Visibility.Visible;
332
_elementText.Text = content.ToString();
336
_elementText.Visibility = Visibility.Collapsed;
341
/// Returns the specified contentPresenter element.
343
/// <param name="index">The index of the desired contentPresenter.</param>
344
/// <returns>The contentPresenter element at the specified index value.</returns>
345
protected virtual DependencyObject GetVisualChild(int index)
349
throw new ArgumentOutOfRangeException("index");
352
object content = Content;
353
return (content == null) ?
355
((content is UIElement) ?