/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / Page.cs / 1 / Page.cs
//----------------------------------------------------------------------------
//
// File: Page.cs
//
// Description: Implements the Avalon Page class
//
// Created: 03/24/03
//
// Copyright (C) 2001 by Microsoft Corporation. All rights reserved.
//
// History:
// 06/11/03 hamidm Moved over to wcp tree
// 08/21/03 huwang Start caching the properties
// 11/20/04 hamidm Adding top level Page concept and implementation.
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Controls.Primitives;
using System.Windows.Navigation;
using System.Windows.Media;
using System.Windows.Markup;
using System.Windows.Documents;
using MS.Internal.AppModel;
using MS.Internal.KnownBoxes;
using MS.Internal;
using MS.Utility;
//In order to avoid generating warnings about unknown message numbers and
//unknown pragmas when compiling your C# source code with the actual C# compiler,
//you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
namespace System.Windows.Controls
{
#region Page Class
///
/// Public class Page
///
[ContentProperty("Content")]
public class Page : FrameworkElement, IWindowService, IAddChild
{
#region Constructors
//----------------------------------------------
//
// Constructors
//
//----------------------------------------------
static Page()
{
// We use IWindowService change notifications to propagate the cached values to the Window
Window.IWindowServiceProperty.OverrideMetadata(
typeof(Page),
new FrameworkPropertyMetadata(new PropertyChangedCallback(_OnWindowServiceChanged)));
// hamidm -- 01/10/2005
// WOSB 1066004 Window/NavigationWindow and Page should not be focusable
// This makes Page non-focusable. If FocusedElement is set on the Page, focus would
// go to that element, otherwise, it will be null. Page taking focus doesn't make
// sense, instead, it should be forwared to some more meaningful element in the tree.
FocusableProperty.OverrideMetadata(typeof(Page), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
DefaultStyleKeyProperty.OverrideMetadata(typeof(Page), new FrameworkPropertyMetadata(typeof(Page)));
_dType = DependencyObjectType.FromSystemTypeInternal(typeof(Page));
}
///
/// Default constructor
///
public Page()
{
// Initialize the _templateCache to the default value for TemplateProperty.
// If the default value is non-null then wire it to the current instance.
PropertyMetadata metadata = TemplateProperty.GetMetadata(DependencyObjectType);
ControlTemplate defaultValue = (ControlTemplate) metadata.DefaultValue;
if (defaultValue != null)
{
OnTemplateChanged(this, new DependencyPropertyChangedEventArgs(TemplateProperty, metadata, null, defaultValue));
}
}
#endregion Constructors
#region IAddChild
///
/// Adds a child. This is called by the parser
///
///
void IAddChild.AddChild(Object obj)
{
VerifyAccess();
// if content is the first child or being cleared, set directly
if (Content == null || obj == null)
{
Content = obj;
}
else
{
throw new InvalidOperationException(SR.Get(SRID.PageCannotHaveMultipleContent));
}
}
///
/// This method is called by the parser when text appears under the tag in markup.
/// By default Page does not support text; calling this method has no effect.
///
///
/// Text to add as a child.
///
void IAddChild.AddText (string str)
{
XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(str, this);
}
#endregion IAddChild
#region LogicalTree
///
/// Returns enumerator to logical children
///
protected internal override IEnumerator LogicalChildren
{
get
{
VerifyAccess();
return new SingleChildEnumerator(Content);
}
}
#endregion LogicalTree
#region Public Properties
///
/// The DependencyProperty for the Content property.
/// Flags: None
/// Default Value: null
///
public static readonly DependencyProperty ContentProperty =
ContentControl.ContentProperty.AddOwner(
typeof(Page),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnContentChanged)));
///
/// Content of the Page
///
///
/// Page only supports one child
///
public Object Content
{
get
{
VerifyAccess();
return GetValue(ContentProperty);
}
set
{
VerifyAccess();
SetValue(ContentProperty, value);
}
}
// All these properties are implemented
// as "bound" to the window service. For
// example, getting WindowTitle will return Window.Title,
// setting WindowTitle will set Window.Title.
//
string IWindowService.Title
{
get
{
VerifyAccess();
if (WindowService == null)
{
#pragma warning disable 6503
throw new InvalidOperationException(SR.Get(SRID.CannotQueryPropertiesWhenPageNotInTreeWithWindow));
#pragma warning restore 6503
}
return WindowService.Title;
}
set
{
VerifyAccess();
if (WindowService == null)
{
PageHelperObject._windowTitle = value;
PropertyIsSet(SetPropertyFlags.WindowTitle);
}
else if (_isTopLevel == true) // only top level page can set this property
{
WindowService.Title = value;
PropertyIsSet(SetPropertyFlags.WindowTitle);
}
}
}
///
/// Proxy for Window Title property
///
[Localizability(LocalizationCategory.Title)]
public string WindowTitle
{
get
{
VerifyAccess();
return ((IWindowService)this).Title;
}
set
{
VerifyAccess();
((IWindowService)this).Title = value;
}
}
internal bool ShouldJournalWindowTitle()
{
return IsPropertySet(SetPropertyFlags.WindowTitle);
}
///
/// Bound to IWindowService property
///
double IWindowService.Height
{
get
{
VerifyAccess();
if (WindowService == null)
{
#pragma warning disable 6503
throw new InvalidOperationException(SR.Get(SRID.CannotQueryPropertiesWhenPageNotInTreeWithWindow));
#pragma warning restore 6503
}
return WindowService.Height;
}
set
{
VerifyAccess();
if (WindowService == null)
{
PageHelperObject._windowHeight = value;
PropertyIsSet(SetPropertyFlags.WindowHeight);
}
else if (_isTopLevel == true)// only top level page can set this property
{
if (!WindowService.UserResized)
{
WindowService.Height = value;
}
PropertyIsSet(SetPropertyFlags.WindowHeight);
}
}
}
///
/// Proxy to Window.Height property
///
public double WindowHeight
{
get
{
VerifyAccess();
return ((IWindowService)this).Height;
}
set
{
VerifyAccess();
((IWindowService)this).Height = value;
}
}
///
/// Proxy to Window.Width property
///
double IWindowService.Width
{
get
{
VerifyAccess();
if (WindowService == null)
{
#pragma warning disable 6503
throw new InvalidOperationException(SR.Get(SRID.CannotQueryPropertiesWhenPageNotInTreeWithWindow));
#pragma warning restore 6503
}
return WindowService.Width;
}
set
{
VerifyAccess();
if (WindowService == null)
{
PageHelperObject._windowWidth = value;
PropertyIsSet(SetPropertyFlags.WindowWidth);
}
else if (_isTopLevel == true) // only top level page can set this property
{
if (!WindowService.UserResized)
{
WindowService.Width = value;
}
PropertyIsSet(SetPropertyFlags.WindowWidth);
}
}
}
///
/// Bound to IWindowService.Width property
///
public double WindowWidth
{
get
{
VerifyAccess();
return ((IWindowService)this).Width;
}
set
{
VerifyAccess();
((IWindowService)this).Width = value;
}
}
///
/// The DependencyProperty for the Background property.
///
public static readonly DependencyProperty BackgroundProperty =
Panel.BackgroundProperty.AddOwner(
typeof(Page),
new FrameworkPropertyMetadata(
Panel.BackgroundProperty.GetDefaultValue(typeof(Panel)),
FrameworkPropertyMetadataOptions.None));
///
/// An object that describes the background.
///
[Category("Appearance")]
public Brush Background
{
get { return (Brush) GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
///
/// The DependencyProperty for the Title property.
///
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register(
"Title", typeof(string), typeof(Page),
new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnTitleChanged)));
///
/// An object that describes the Title.
///
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
// If the Title has changed we want to set the flag.
static private void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((Page)d).PropertyIsSet(SetPropertyFlags.Title);
}
///
/// Determines whether to show the default navigation UI.
///
public bool ShowsNavigationUI
{
get
{
VerifyAccess();
if (WindowService == null)
{
#pragma warning disable 6503
throw new InvalidOperationException(SR.Get(SRID.CannotQueryPropertiesWhenPageNotInTreeWithWindow));
#pragma warning restore 6503
}
// Return false if it is not NavigationWindow.
NavigationWindow navWin = WindowService as NavigationWindow;
if (navWin != null)
{
return navWin.ShowsNavigationUI;
}
else
{
return false;
}
}
set
{
VerifyAccess();
if (WindowService == null)
{
PageHelperObject._showsNavigationUI = value;
PropertyIsSet(SetPropertyFlags.ShowsNavigationUI);
}
else if (_isTopLevel == true) // only top level page can set this property
{
SetShowsNavigationUI(value);
PropertyIsSet(SetPropertyFlags.ShowsNavigationUI);
}
}
}
///
/// The DependencyProperty for the KeepAlive property.
///
public static readonly DependencyProperty KeepAliveProperty =
JournalEntry.KeepAliveProperty.AddOwner(typeof(Page));
///
/// An object that describes the KeepAlive status of the Page.
///
public bool KeepAlive
{
get
{
return JournalEntry.GetKeepAlive(this);
}
set
{
JournalEntry.SetKeepAlive(this, value);
}
}
///
/// NavigationServiceProperty
///
public NavigationService NavigationService
{
get
{
return NavigationService.GetNavigationService(this);
}
}
///
/// The DependencyProperty for the Foreground property.
/// Flags: Can be used in style rules
/// Default Value: System Font Color
///
public static readonly DependencyProperty ForegroundProperty =
TextElement.ForegroundProperty.AddOwner(typeof(Page));
///
/// An brush that describes the foreground color which is used by
/// via inheritance.
///
[Bindable(true), Category("Appearance")]
public Brush Foreground
{
get { return (Brush) GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
///
/// The DependencyProperty for the FontFamily property.
/// Flags: Can be used in style rules
/// Default Value: System Dialog Font
///
public static readonly DependencyProperty FontFamilyProperty =
TextElement.FontFamilyProperty.AddOwner(typeof(Page));
///
/// The font family of the desired font which is used via inheritance
///
[Bindable(true), Category("Appearance")]
[Localizability(
LocalizationCategory.Font,
Modifiability = Modifiability.Unmodifiable
)]
public FontFamily FontFamily
{
get { return (FontFamily) GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
///
/// The DependencyProperty for the FontSize property.
/// Flags: Can be used in style rules
/// Default Value: System Dialog Font Size
///
public static readonly DependencyProperty FontSizeProperty =
TextElement.FontSizeProperty.AddOwner(typeof(Page));
///
/// The size of the desired font which will be used via inheritance.
///
[TypeConverter(typeof(FontSizeConverter))]
[Bindable(true), Category("Appearance")]
[Localizability(LocalizationCategory.None)] // FontSize is localizable
public double FontSize
{
get { return (double) GetValue(FontSizeProperty); }
set { SetValue(FontSizeProperty, value); }
}
///
/// TemplateProperty
///
public static readonly DependencyProperty TemplateProperty =
Control.TemplateProperty.AddOwner(
typeof(Page),
new FrameworkPropertyMetadata(
(ControlTemplate) null, // default value
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(OnTemplateChanged)));
///
/// Template Property
///
public ControlTemplate Template
{
get { return _templateCache; }
set { SetValue(TemplateProperty, value); }
}
// Internal Helper so the FrameworkElement could see this property
internal override FrameworkTemplate TemplateInternal
{
get { return Template; }
}
// Internal Helper so the FrameworkElement could see the template cache
internal override FrameworkTemplate TemplateCache
{
get { return _templateCache; }
set { _templateCache = (ControlTemplate)value; }
}
// Internal helper so FrameworkElement could see call the template changed virtual
internal override void OnTemplateChangedInternal(FrameworkTemplate oldTemplate, FrameworkTemplate newTemplate)
{
OnTemplateChanged((ControlTemplate)oldTemplate, (ControlTemplate)newTemplate);
}
// Property invalidation callback invoked when TemplateProperty is changed
private static void OnTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Page p = (Page) d;
StyleHelper.UpdateTemplateCache(p, (FrameworkTemplate) e.OldValue, (FrameworkTemplate) e.NewValue, TemplateProperty);
}
///
/// Template has changed
///
///
/// When a Template changes, the VisualTree is removed. The new Template's
/// VisualTree will be created when ApplyTemplate is called
///
/// The old Template
/// The new Template
protected virtual void OnTemplateChanged(
ControlTemplate oldTemplate, ControlTemplate newTemplate)
{
}
#endregion Public Properties
//---------------------------------------------------
//
// Public Events
//
//---------------------------------------------------
//----------------------------------------------------
//
// Protected Methods
//
//---------------------------------------------------
#region Protected Methods
///
/// Measurement override.
///
///
/// Sizing constraint.
///
protected override Size MeasureOverride(Size constraint)
{
VerifyAccess();
int count = this.VisualChildrenCount;
if (count > 0)
{
UIElement child = this.GetVisualChild(0) as UIElement;
if (child != null)
{
child.Measure(constraint);
return child.DesiredSize;
}
}
return (new Size(0, 0));
}
///
/// ArrangeOverride allows for the customization of the positioning of children.
///
///
/// Measured size.
///
protected override Size ArrangeOverride(Size arrangeBounds)
{
VerifyAccess();
int count = this.VisualChildrenCount;
if (count > 0)
{
UIElement child = this.GetVisualChild(0) as UIElement;
if (child != null)
{
child.Arrange(new Rect(new Point(), arrangeBounds));
}
}
return arrangeBounds;
}
///
/// OnVisualParentChanged is called when the parent of the Visual is changed.
///
/// Old parent or null if the Visual did not have a parent before.
protected internal sealed override void OnVisualParentChanged(DependencyObject oldParent)
{
VerifyAccess();
base.OnVisualParentChanged(oldParent);
// When Page is added to a tree, it can only be the root element of Window's or Frame's Content.
// In code, it means you can only add Page to a tree via Window.Content = Page, Frame.Content = Page,
// or equivalent such as navigation.
// So we only allow a Page to be parented by a Visual (parent) in the following
// cases:
// 1. The visual parent is null.
// 2. The logical parent is Window (Frame's Content is not its logical child).
// 3. When the logical parent is not Window, it can only be the case of Page inside of a Frame. We can verify that
// by checking the Content of the Page's NavigationService is the Page itself.
// The NavigationService dp and its Content property both are set before logical and/or visual Parent change.
// 4. Exception should be thrown in any other situations, except for the v1 compatibility case below.
Visual visualParent = VisualTreeHelper.GetParent(this) as Visual;
// Need to check whether visual parent is null first, because if the app caught the exception as a result of setting illegal parent,
// and it removes the Page from the wrongly set parent, the visual link is removed first before the logical link.
// As a result when OnVisualParentChanged is fired, visualParent is null while the logical Parent is still the old one; Parent getter
// here will return the illegal one.
if ((visualParent == null) ||
(Parent is Window) ||
((NavigationService != null) && (NavigationService.Content == this)))
{
return;
}
// NOTE (Huwang 03/09/2007): The code below walks up the TemplatedParent chain until it finds the first Frame or Window. It does not
// check whether Window.Content or Frame.Content is Page. So it allows the scenario where Page can be in any element’s template and
// be parented by any element as long as the template is nested inside a Window or Frame, as demoed below
//
//
//
// ...
//