Browse Source

Added IsTemplateFocusTarget attached property.

And use it in TreeViewItem's data template to place the focus adorner
around the correct control. Closes #294.
pull/417/head
Steven Kirk 11 years ago
parent
commit
f004a0a778
  1. 21
      src/Perspex.Controls/Control.cs
  2. 48
      src/Perspex.Controls/Primitives/TemplatedControl.cs
  3. 6
      src/Perspex.Controls/Templates/TemplateExtensions.cs
  4. 8
      src/Perspex.Themes.Default/TreeViewItem.paml

21
src/Perspex.Controls/Control.cs

@ -69,8 +69,7 @@ namespace Perspex.Controls
/// Defines the <see cref="ContextMenu"/> property.
/// </summary>
public static readonly StyledProperty<ContextMenu> ContextMenuProperty =
PerspexProperty.Register<Control, ContextMenu>(nameof(ContextMenu));
PerspexProperty.Register<Control, ContextMenu>(nameof(ContextMenu));
/// <summary>
/// Event raised when an element wishes to be scrolled into view.
@ -393,6 +392,15 @@ namespace Perspex.Controls
});
}
/// <summary>
/// Gets the element that recieves the focus adorner.
/// </summary>
/// <returns>The control that recieves the focus adorner.</returns>
protected virtual IControl GetTemplateFocusTarget()
{
return this;
}
/// <summary>
/// Called when the control is added to a logical tree.
/// </summary>
@ -488,8 +496,13 @@ namespace Perspex.Controls
if (_focusAdorner != null)
{
AdornerLayer.SetAdornedElement((Visual)_focusAdorner, this);
adornerLayer.Children.Add(_focusAdorner);
var target = (Visual)GetTemplateFocusTarget();
if (target != null)
{
AdornerLayer.SetAdornedElement((Visual)_focusAdorner, target);
adornerLayer.Children.Add(_focusAdorner);
}
}
}
}

48
src/Perspex.Controls/Primitives/TemplatedControl.cs

@ -74,6 +74,12 @@ namespace Perspex.Controls.Primitives
public static readonly StyledProperty<IControlTemplate> TemplateProperty =
PerspexProperty.Register<TemplatedControl, IControlTemplate>("Template");
/// <summary>
/// Defines the IsTemplateFocusTarget attached property.
/// </summary>
public static readonly AttachedProperty<bool> IsTemplateFocusTargetProperty =
PerspexProperty.RegisterAttached<TemplatedControl, Control, bool>("IsTemplateFocusTarget");
/// <summary>
/// Defines the <see cref="TemplateApplied"/> routed event.
/// </summary>
@ -198,6 +204,33 @@ namespace Perspex.Controls.Primitives
set { SetValue(TemplateProperty, value); }
}
/// <summary>
/// Gets the value of the IsTemplateFocusTargetProperty attached property on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The property value.</returns>
/// <see cref="SetIsTemplateFocusTarget(Control, bool)"/>
public bool GetIsTemplateFocusTarget(Control control)
{
return control.GetValue(IsTemplateFocusTargetProperty);
}
/// <summary>
/// Sets the value of the IsTemplateFocusTargetProperty attached property on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value.</param>
/// <remarks>
/// When a control is navigated to using the keyboard, a focus adorner is shown - usually
/// around the control itself. However if the TemplatedControl.IsTemplateFocusTarget
/// attached property is set to true on an element in the control template, then the focus
/// adorner will be shown around that control instead.
/// </remarks>
public void SetIsTemplateFocusTarget(Control control, bool value)
{
control.SetValue(IsTemplateFocusTargetProperty, value);
}
/// <inheritdoc/>
public sealed override void ApplyTemplate()
{
@ -224,6 +257,7 @@ namespace Perspex.Controls.Primitives
}
}
/// <inheritdoc/>
protected sealed override IndexerDescriptor CreateBindingDescriptor(IndexerDescriptor source)
{
var result = base.CreateBindingDescriptor(source);
@ -240,6 +274,20 @@ namespace Perspex.Controls.Primitives
return result;
}
/// <inheritdoc/>
protected override IControl GetTemplateFocusTarget()
{
foreach (Control child in this.GetTemplateChildren())
{
if (GetIsTemplateFocusTarget(child))
{
return child;
}
}
return this;
}
/// <summary>
/// Called when the control's template is applied.
/// </summary>

6
src/Perspex.Controls/Templates/TemplateExtensions.cs

@ -12,7 +12,7 @@ namespace Perspex.Controls.Templates
{
public static class TemplateExtensions
{
public static IEnumerable<Control> GetTemplateChildren(this ITemplatedControl control)
public static IEnumerable<IControl> GetTemplateChildren(this ITemplatedControl control)
{
var visual = control as IVisual;
@ -21,12 +21,12 @@ namespace Perspex.Controls.Templates
// TODO: This searches the whole descendent tree - it can stop when it exits the
// template.
return visual.GetVisualDescendents()
.OfType<Control>()
.OfType<IControl>()
.Where(x => x.TemplatedParent == control);
}
else
{
return Enumerable.Empty<Control>();
return Enumerable.Empty<IControl>();
}
}
}

8
src/Perspex.Themes.Default/TreeViewItem.paml

@ -11,18 +11,12 @@
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>
<Rectangle Name="focus"
IsHitTestVisible="False"
IsVisible="{TemplateBinding IsFocused}"
Stroke="Black"
StrokeThickness="1"
StrokeDashArray="1,2"
Grid.Column="1"/>
</Grid>
<ItemsPresenter Name="PART_ItemsPresenter"
IsVisible="{TemplateBinding IsExpanded}"

Loading…
Cancel
Save