Browse Source

Optimize ContentPresenter.

Make ContentPresenter have many of Border's properties so that every
instance of a ContentPresenter doesn't need to be wrapped in a Border.
Idea stolen from UWP.
pull/472/head
Steven Kirk 10 years ago
parent
commit
5802040d3e
  1. 188
      src/Perspex.Controls/Presenters/ContentPresenter.cs
  2. 14
      src/Perspex.Layout/Layoutable.cs
  3. 24
      src/Perspex.Themes.Default/Button.xaml
  4. 13
      src/Perspex.Themes.Default/ContentControl.xaml
  5. 18
      src/Perspex.Themes.Default/DropDownItem.xaml
  6. 18
      src/Perspex.Themes.Default/ListBoxItem.xaml
  7. 9
      src/Perspex.Themes.Default/PopupRoot.xaml
  8. 11
      src/Perspex.Themes.Default/TabStripItem.xaml
  9. 28
      src/Perspex.Themes.Default/ToggleButton.xaml
  10. 13
      src/Perspex.Themes.Default/ToolTip.xaml
  11. 24
      src/Perspex.Themes.Default/TreeViewItem.xaml

188
src/Perspex.Controls/Presenters/ContentPresenter.cs

@ -1,9 +1,12 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Layout;
using Perspex.LogicalTree;
using Perspex.Media;
namespace Perspex.Controls.Presenters
{
@ -12,6 +15,24 @@ namespace Perspex.Controls.Presenters
/// </summary>
public class ContentPresenter : Control, IContentPresenter
{
/// <summary>
/// Defines the <see cref="Background"/> property.
/// </summary>
public static readonly StyledProperty<Brush> BackgroundProperty =
Border.BackgroundProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="BorderBrush"/> property.
/// </summary>
public static readonly PerspexProperty<Brush> BorderBrushProperty =
Border.BorderBrushProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="BorderThickness"/> property.
/// </summary>
public static readonly StyledProperty<double> BorderThicknessProperty =
Border.BorderThicknessProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="Child"/> property.
/// </summary>
@ -26,6 +47,30 @@ namespace Perspex.Controls.Presenters
public static readonly StyledProperty<object> ContentProperty =
ContentControl.ContentProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="CornerRadius"/> property.
/// </summary>
public static readonly StyledProperty<float> CornerRadiusProperty =
Border.CornerRadiusProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="HorizontalContentAlignment"/> property.
/// </summary>
public static readonly StyledProperty<HorizontalAlignment> HorizontalContentAlignmentProperty =
ContentControl.HorizontalContentAlignmentProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="VerticalContentAlignment"/> property.
/// </summary>
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
ContentControl.VerticalContentAlignmentProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="Padding"/> property.
/// </summary>
public static readonly StyledProperty<Thickness> PaddingProperty =
Border.PaddingProperty.AddOwner<ContentPresenter>();
private IControl _child;
private bool _createdChild;
@ -38,6 +83,33 @@ namespace Perspex.Controls.Presenters
TemplatedParentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.TemplatedParentChanged);
}
/// <summary>
/// Gets or sets a brush with which to paint the background.
/// </summary>
public Brush Background
{
get { return GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
/// <summary>
/// Gets or sets a brush with which to paint the border.
/// </summary>
public Brush BorderBrush
{
get { return GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); }
}
/// <summary>
/// Gets or sets the thickness of the border.
/// </summary>
public double BorderThickness
{
get { return GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
/// <summary>
/// Gets the control displayed by the presenter.
/// </summary>
@ -56,6 +128,42 @@ namespace Perspex.Controls.Presenters
set { SetValue(ContentProperty, value); }
}
/// <summary>
/// Gets or sets the radius of the border rounded corners.
/// </summary>
public float CornerRadius
{
get { return GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Gets or sets the horizontal alignment of the content within the control.
/// </summary>
public HorizontalAlignment HorizontalContentAlignment
{
get { return GetValue(HorizontalContentAlignmentProperty); }
set { SetValue(HorizontalContentAlignmentProperty, value); }
}
/// <summary>
/// Gets or sets the vertical alignment of the content within the control.
/// </summary>
public VerticalAlignment VerticalContentAlignment
{
get { return GetValue(VerticalContentAlignmentProperty); }
set { SetValue(VerticalContentAlignmentProperty, value); }
}
/// <summary>
/// Gets or sets the padding to place around the <see cref="Child"/> control.
/// </summary>
public Thickness Padding
{
get { return GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
/// <inheritdoc/>
public override sealed void ApplyTemplate()
{
@ -120,23 +228,93 @@ namespace Perspex.Controls.Presenters
}
/// <inheritdoc/>
protected override Size MeasureCore(Size availableSize)
public override void Render(DrawingContext context)
{
return base.MeasureCore(availableSize);
var background = Background;
var borderBrush = BorderBrush;
var borderThickness = BorderThickness;
var cornerRadius = CornerRadius;
var rect = new Rect(Bounds.Size).Deflate(BorderThickness);
if (background != null)
{
context.FillRectangle(background, rect, cornerRadius);
}
if (borderBrush != null && borderThickness > 0)
{
context.DrawRectangle(new Pen(borderBrush, borderThickness), rect, cornerRadius);
}
}
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
var child = Child;
var padding = Padding + new Thickness(BorderThickness);
if (child != null)
{
child.Measure(availableSize);
return child.DesiredSize;
child.Measure(availableSize.Deflate(padding));
return child.DesiredSize.Inflate(padding);
}
else
{
return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
}
}
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
var child = Child;
if (child != null)
{
var padding = Padding + new Thickness(BorderThickness);
var sizeMinusPadding = finalSize.Deflate(padding);
var size = sizeMinusPadding;
var horizontalAlignment = HorizontalContentAlignment;
var verticalAlignment = VerticalContentAlignment;
var originX = padding.Left;
var originY = padding.Top;
if (horizontalAlignment != HorizontalAlignment.Stretch)
{
size = size.WithWidth(child.DesiredSize.Width);
}
if (verticalAlignment != VerticalAlignment.Stretch)
{
size = size.WithHeight(child.DesiredSize.Height);
}
switch (horizontalAlignment)
{
case HorizontalAlignment.Stretch:
case HorizontalAlignment.Center:
originX += (sizeMinusPadding.Width - size.Width) / 2;
break;
case HorizontalAlignment.Right:
originX = size.Width - child.DesiredSize.Width;
break;
}
switch (verticalAlignment)
{
case VerticalAlignment.Stretch:
case VerticalAlignment.Center:
originY += (sizeMinusPadding.Height - size.Height) / 2;
break;
case VerticalAlignment.Bottom:
originY = size.Height - child.DesiredSize.Height;
break;
}
child.Arrange(new Rect(originX, originY, size.Width, size.Height));
}
return new Size();
return finalSize;
}
/// <summary>

14
src/Perspex.Layout/Layoutable.cs

@ -536,20 +536,22 @@ namespace Perspex.Layout
{
if (IsVisible)
{
double originX = finalRect.X + Margin.Left;
double originY = finalRect.Y + Margin.Top;
var originX = finalRect.X + Margin.Left;
var originY = finalRect.Y + Margin.Top;
var sizeMinusMargins = new Size(
Math.Max(0, finalRect.Width - Margin.Left - Margin.Right),
Math.Max(0, finalRect.Height - Margin.Top - Margin.Bottom));
var horizontalAlignment = HorizontalAlignment;
var verticalAlignment = VerticalAlignment;
var size = sizeMinusMargins;
var scale = GetLayoutScale();
if (HorizontalAlignment != HorizontalAlignment.Stretch)
if (horizontalAlignment != HorizontalAlignment.Stretch)
{
size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width));
}
if (VerticalAlignment != VerticalAlignment.Stretch)
if (verticalAlignment != VerticalAlignment.Stretch)
{
size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height));
}
@ -568,7 +570,7 @@ namespace Perspex.Layout
size = ArrangeOverride(size).Constrain(size);
switch (HorizontalAlignment)
switch (horizontalAlignment)
{
case HorizontalAlignment.Center:
case HorizontalAlignment.Stretch:
@ -579,7 +581,7 @@ namespace Perspex.Layout
break;
}
switch (VerticalAlignment)
switch (verticalAlignment)
{
case VerticalAlignment.Center:
case VerticalAlignment.Stretch:

24
src/Perspex.Themes.Default/Button.xaml

@ -9,24 +9,22 @@
<Setter Property="Padding" Value="4"/>
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Button:pointerover /template/ Border#border">
<Style Selector="Button:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="Button:pressed /template/ Border#border">
<Style Selector="Button:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{StyleResource ThemeControlDarkBrush}"/>
</Style>
<Style Selector="Button:disabled">

13
src/Perspex.Themes.Default/ContentControl.xaml

@ -1,13 +1,12 @@
<Style xmlns="https://github.com/perspex" Selector="ContentControl">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>

18
src/Perspex.Themes.Default/DropDownItem.xaml

@ -3,21 +3,19 @@
<Setter Property="Padding" Value="2"/>
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="DropDownItem:selected /template/ Border#border">
<Style Selector="DropDownItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="#fff0f0f0"/>
</Style>
<Style Selector="DropDownItem:pointerover /template/ Border#border">
<Style Selector="DropDownItem:pointerover /template/ ContentPresenter">
<Setter Property="Background" Value="#ffd0d0d0"/>
</Style>
</Styles>

18
src/Perspex.Themes.Default/ListBoxItem.xaml

@ -2,21 +2,19 @@
<Style Selector="ListBoxItem">
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ListBoxItem:selected /template/ Border#border">
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="Background" Value="#fff0f0f0"/>
</Style>
<Style Selector="ListBoxItem:selected:focus /template/ Border#border">
<Style Selector="ListBoxItem:selected:focus /template/ ContentPresenter">
<Setter Property="Background" Value="#ffd0d0d0"/>
</Style>
</Styles>

9
src/Perspex.Themes.Default/PopupRoot.xaml

@ -2,11 +2,10 @@
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>

11
src/Perspex.Themes.Default/TabStripItem.xaml

@ -4,13 +4,12 @@
<Setter Property="Foreground" Value="{StyleResource ThemeForegroundLightBrush}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>

28
src/Perspex.Themes.Default/ToggleButton.xaml

@ -4,33 +4,31 @@
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderLightBrush}"/>
<Setter Property="BorderThickness" Value="{StyleResource ThemeBorderThickness}"/>
<Setter Property="Foreground" Value="{StyleResource ThemeForegroundBrush}"/>
<Setter Property="Padding" Value="4"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
Padding="3"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ToggleButton:checked /template/ Border#border">
<Style Selector="ToggleButton:checked /template/ ContentPresenter">
<Setter Property="Background" Value="{StyleResource ThemeControlDarkBrush}"/>
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="ToggleButton:pointerover /template/ Border#border">
<Style Selector="ToggleButton:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="ToggleButton:pressed /template/ Border#border">
<Style Selector="ToggleButton:pressed /template/ ContentPresenter">
<Setter Property="Background" Value="{StyleResource ThemeControlDarkBrush}"/>
</Style>
<Style Selector="ToggleButton:disabled">

13
src/Perspex.Themes.Default/ToolTip.xaml

@ -5,13 +5,12 @@
<Setter Property="Padding" Value="4,2"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>
</Style>

24
src/Perspex.Themes.Default/TreeViewItem.xaml

@ -7,16 +7,14 @@
<ToggleButton Name="expander"
Focusable="False"
IsChecked="{TemplateBinding Path=IsExpanded, Mode=TwoWay}"/>
<Border Name="header"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
TemplatedControl.IsTemplateFocusTarget="True"
Grid.Column="1">
<ContentPresenter Name="PART_HeaderPresenter"
Content="{TemplateBinding Header}"
Margin="{TemplateBinding Padding}"/>
</Border>
<ContentPresenter Name="PART_HeaderPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Header}"
Padding="{TemplateBinding Padding}"
TemplatedControl.IsTemplateFocusTarget="True"
Grid.Column="1"/>
</Grid>
<ItemsPresenter Name="PART_ItemsPresenter"
IsVisible="{TemplateBinding IsExpanded}"
@ -45,15 +43,15 @@
</Setter>
</Style>
<Style Selector="TreeViewItem /template/ Border#header">
<Style Selector="TreeViewItem /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="Padding" Value="2"/>
</Style>
<Style Selector="TreeViewItem:selected /template/ Border#header">
<Style Selector="TreeViewItem:selected /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="Background" Value="#fff0f0f0"/>
</Style>
<Style Selector="TreeViewItem:selected:focus /template/ Border#header">
<Style Selector="TreeViewItem:selected:focus /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="Background" Value="#ffd0d0d0"/>
</Style>

Loading…
Cancel
Save