Browse Source

Merge from upstream

pull/65/head
Nelson Carrillo 11 years ago
parent
commit
2074e18294
  1. 25
      Perspex.Controls/ListBoxItem.cs
  2. 8
      Perspex.Controls/MenuItem.cs
  3. 70
      Perspex.Controls/Mixins/SelectableMixin.cs
  4. 1
      Perspex.Controls/Perspex.Controls.csproj
  5. 16
      Perspex.Controls/TabItem.cs
  6. 37
      Perspex.Controls/TreeViewItem.cs
  7. 2
      Perspex.Themes.Default/ListBoxItemStyle.cs
  8. 2
      Perspex.Themes.Default/MenuItemStyle.cs
  9. 2
      Perspex.Themes.Default/TabItemStyle.cs
  10. 2
      Perspex.Themes.Default/TreeViewItemStyle.cs
  11. 4
      Tests/Perspex.Controls.UnitTests/GlobalSuppressions.cs
  12. 76
      Tests/Perspex.Controls.UnitTests/Mixins/SelectableMixinTests.cs
  13. 1
      Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

25
Perspex.Controls/ListBoxItem.cs

@ -1,17 +1,15 @@
// -----------------------------------------------------------------------
// <copyright file="ListBoxItem.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
using System;
using Perspex.Controls.Primitives;
using Perspex.Interactivity;
using Perspex.Controls.Mixins;
/// <summary>
/// An selectable item in a <see cref="ListBox"/>.
/// A selectable item in a <see cref="ListBox"/>.
/// </summary>
public class ListBoxItem : ContentControl, ISelectable
{
@ -26,8 +24,7 @@ namespace Perspex.Controls
/// </summary>
static ListBoxItem()
{
Control.PseudoClass(IsSelectedProperty, ":selected");
IsSelectedProperty.Changed.Subscribe(IsSelectedChanged);
SelectableMixin.Attach<ListBoxItem>(IsSelectedProperty);
}
/// <summary>
@ -38,19 +35,5 @@ namespace Perspex.Controls
get { return this.GetValue(IsSelectedProperty); }
set { this.SetValue(IsSelectedProperty, value); }
}
/// <summary>
/// Called when the <see cref="IsSelected"/> property changes on an object.
/// </summary>
/// <param name="e">The sender.</param>
private static void IsSelectedChanged(PerspexPropertyChangedEventArgs e)
{
var interactive = e.Sender as IInteractive;
if (interactive != null)
{
interactive.RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
}
}
}
}

8
Perspex.Controls/MenuItem.cs

@ -10,13 +10,14 @@ namespace Perspex.Controls
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using Perspex.Controls.Mixins;
using Perspex.Controls.Presenters;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Input;
using Perspex.Interactivity;
using Perspex.Controls.Templates;
using Perspex.Controls.Presenters;
using Perspex.VisualTree;
using Perspex.Threading;
using Perspex.VisualTree;
using Splat;
/// <summary>
@ -87,6 +88,7 @@ namespace Perspex.Controls
/// </summary>
static MenuItem()
{
SelectableMixin.Attach<MenuItem>(IsSelectedProperty);
FocusableProperty.OverrideDefaultValue<MenuItem>(true);
ClickEvent.AddClassHandler<MenuItem>(x => x.OnClick);
SubmenuOpenedEvent.AddClassHandler<MenuItem>(x => x.OnSubmenuOpened);

70
Perspex.Controls/Mixins/SelectableMixin.cs

@ -0,0 +1,70 @@
// -----------------------------------------------------------------------
// <copyright file="SelectableMixin.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.Mixins
{
using System;
using Perspex.Interactivity;
using Primitives;
/// <summary>
/// Adds selectable functionality to control classes.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="SelectableMixin{TControl}"/> adds behavior to a control which can be
/// selected. It adds the following behavior:
/// </para>
/// <list type="bullet">
/// <item>
/// Raises an <see cref="SelectingItemsControl.IsSelectedChangedEvent"/> when the value if
/// the IsSelected property changes.
/// </item>
/// <item>
/// Adds a 'selected' class to selected controls.
/// </item>
/// </list>
/// <para>
/// Mixins apply themselves to classes and not instances, and as such should be created in
/// a static constructor.
/// </para>
/// </remarks>
public static class SelectableMixin
{
/// <summary>
/// Initializes a new instance of the <see cref="SelectableMixin{TControl}"/> class.
/// </summary>
/// <typeparam name="TControl">The control type.</typeparam>
/// <param name="isSelected">The IsSelected property.</param>
public static void Attach<TControl>(PerspexProperty<bool> isSelected)
where TControl : class, IControl
{
Contract.Requires<ArgumentNullException>(isSelected != null);
isSelected.Changed.Subscribe(x =>
{
var sender = x.Sender as TControl;
if (sender != null)
{
if ((bool)x.NewValue)
{
sender.Classes.Add("selected");
}
else
{
sender.Classes.Remove("selected");
}
sender.RaiseEvent(new RoutedEventArgs
{
RoutedEvent = SelectingItemsControl.IsSelectedChangedEvent
});
}
});
}
}
}

1
Perspex.Controls/Perspex.Controls.csproj

@ -39,6 +39,7 @@
<Compile Include="IControl.cs" />
<Compile Include="ISetLogicalParent.cs" />
<Compile Include="MenuItemAccessKeyHandler.cs" />
<Compile Include="Mixins\SelectableMixin.cs" />
<Compile Include="Parsers\GridLengthsParser.cs" />
<Compile Include="Primitives\AccessText.cs" />
<Compile Include="Border.cs" />

16
Perspex.Controls/TabItem.cs

@ -6,20 +6,32 @@
namespace Perspex.Controls
{
using Mixins;
using Perspex.Controls.Primitives;
/// <summary>
/// An item in a <see cref="TabStrip"/> or <see cref="TabControl"/>.
/// </summary>
public class TabItem : HeaderedContentControl, ISelectable
{
/// <summary>
/// Defines the <see cref="IsSelected"/> property.
/// </summary>
public static readonly PerspexProperty<bool> IsSelectedProperty =
ListBoxItem.IsSelectedProperty.AddOwner<TabItem>();
/// <summary>
/// Initializes static members of the <see cref="TabItem"/> class.
/// </summary>
static TabItem()
{
SelectableMixin.Attach<TabItem>(IsSelectedProperty);
FocusableProperty.OverrideDefaultValue(typeof(TabItem), true);
Control.AffectsRender(IsSelectedProperty);
Control.PseudoClass(IsSelectedProperty, ":selected");
}
/// <summary>
/// Gets or sets the selection state of the item.
/// </summary>
public bool IsSelected
{
get { return this.GetValue(IsSelectedProperty); }

37
Perspex.Controls/TreeViewItem.cs

@ -1,6 +1,6 @@
// -----------------------------------------------------------------------
// <copyright file="TreeViewItem.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
@ -8,56 +8,75 @@ namespace Perspex.Controls
{
using System;
using System.Linq;
using Mixins;
using Perspex.Controls.Generators;
using Perspex.Controls.Primitives;
using Perspex.Rendering;
using Perspex.VisualTree;
/// <summary>
/// An item in a <see cref="TreeView"/>.
/// </summary>
public class TreeViewItem : HeaderedItemsControl, ISelectable
{
/// <summary>
/// Defines the <see cref="IsExpanded"/> property.
/// </summary>
public static readonly PerspexProperty<bool> IsExpandedProperty =
PerspexProperty.Register<TreeViewItem, bool>("IsExpanded");
/// <summary>
/// Defines the <see cref="IsSelected"/> property.
/// </summary>
public static readonly PerspexProperty<bool> IsSelectedProperty =
ListBoxItem.IsSelectedProperty.AddOwner<TreeViewItem>();
private TreeView treeView;
/// <summary>
/// Initializes static members of the <see cref="TreeViewItem"/> class.
/// </summary>
static TreeViewItem()
{
Control.PseudoClass(IsSelectedProperty, ":selected");
}
public TreeViewItem()
{
Control.AffectsRender(IsSelectedProperty);
SelectableMixin.Attach<TreeViewItem>(IsSelectedProperty);
}
/// <summary>
/// Gets or sets a value indicating whether the item is expanded to show its children.
/// </summary>
public bool IsExpanded
{
get { return this.GetValue(IsExpandedProperty); }
set { this.SetValue(IsExpandedProperty, value); }
}
/// <summary>
/// Gets or sets the selection state of the item.
/// </summary>
public bool IsSelected
{
get { return this.GetValue(IsSelectedProperty); }
set { this.SetValue(IsSelectedProperty, value); }
}
/// <inheritdoc/>
protected override ItemContainerGenerator CreateItemContainerGenerator()
{
if (this.treeView == null)
{
throw new InvalidOperationException(
"Cannot get the ItemContainerGenerator for a TreeViewItem " +
"Cannot get the ItemContainerGenerator for a TreeViewItem " +
"before it is added to a TreeView.");
}
return this.treeView.ItemContainerGenerator;
}
protected override void OnVisualParentChanged(Visual oldParent)
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(IRenderRoot root)
{
base.OnAttachedToVisualTree(root);
if (this.GetVisualParent() != null)
{
this.treeView = this.GetVisualAncestors().OfType<TreeView>().FirstOrDefault();

2
Perspex.Themes.Default/ListBoxItemStyle.cs

@ -25,7 +25,7 @@ namespace Perspex.Themes.Default
new Setter(ListBoxItem.TemplateProperty, ControlTemplate.Create<ListBoxItem>(this.Template)),
},
},
new Style(x => x.OfType<ListBoxItem>().Class(":selected").Template().Name("border"))
new Style(x => x.OfType<ListBoxItem>().Class("selected").Template().Name("border"))
{
Setters = new[]
{

2
Perspex.Themes.Default/MenuItemStyle.cs

@ -41,7 +41,7 @@ namespace Perspex.Themes.Default
new Setter(MenuItem.TemplateProperty, ControlTemplate.Create<MenuItem>(this.TopLevelTemplate)),
},
},
new Style(x => x.OfType<MenuItem>().Class(":selected").Template().Name("root"))
new Style(x => x.OfType<MenuItem>().Class("selected").Template().Name("root"))
{
Setters = new[]
{

2
Perspex.Themes.Default/TabItemStyle.cs

@ -27,7 +27,7 @@ namespace Perspex.Themes.Default
new Setter(TabItem.TemplateProperty, ControlTemplate.Create<TabItem>(this.Template)),
},
},
new Style(x => x.OfType<TabItem>().Class(":selected"))
new Style(x => x.OfType<TabItem>().Class("selected"))
{
Setters = new[]
{

2
Perspex.Themes.Default/TreeViewItemStyle.cs

@ -35,7 +35,7 @@ namespace Perspex.Themes.Default
new Setter(Border.PaddingProperty, new Thickness(2)),
},
},
new Style(x => x.OfType<TreeViewItem>().Class(":selected").Template().Name("header"))
new Style(x => x.OfType<TreeViewItem>().Class("selected").Template().Name("header"))
{
Setters = new[]
{

4
Tests/Perspex.Controls.UnitTests/GlobalSuppressions.cs

@ -3,6 +3,10 @@
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(
"StyleCop.CSharp.MaintainabilityRules",
"SA1401:Fields must be private",
Justification = "PerspexProperty fields should not be private.")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(
"StyleCop.CSharp.DocumentationRules",
"SA1600:Elements must be documented",

76
Tests/Perspex.Controls.UnitTests/Mixins/SelectableMixinTests.cs

@ -0,0 +1,76 @@
// -----------------------------------------------------------------------
// <copyright file="SelectableMixinTests.cs" company="Steven Kirk">
// Copyright 2015 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.UnitTests.Mixins
{
using Perspex.Controls.Mixins;
using Perspex.Controls.Primitives;
using Xunit;
public class SelectableMixinTests
{
[Fact]
public void Selected_Class_Should_Not_Initially_Be_Added()
{
var target = new TestControl();
Assert.Empty(target.Classes);
}
[Fact]
public void Setting_IsSelected_Should_Add_Selected_Class()
{
var target = new TestControl();
target.IsSelected = true;
Assert.Equal(new[] { "selected" }, target.Classes);
}
[Fact]
public void Clearing_IsSelected_Should_Remove_Selected_Class()
{
var target = new TestControl();
target.IsSelected = true;
target.IsSelected = false;
Assert.Empty(target.Classes);
}
[Fact]
public void Setting_IsSelected_Should_Raise_IsSelectedChangedEvent()
{
var target = new TestControl();
var raised = false;
target.AddHandler(
SelectingItemsControl.IsSelectedChangedEvent,
(s, e) => raised = true);
target.IsSelected = true;
Assert.True(raised);
}
private class TestControl : Control, ISelectable
{
public static readonly PerspexProperty<bool> IsSelectedProperty =
PerspexProperty.Register<TestControl, bool>(nameof(IsSelected));
static TestControl()
{
SelectableMixin.Attach<TestControl>(IsSelectedProperty);
}
public bool IsSelected
{
get { return this.GetValue(IsSelectedProperty); }
set { this.SetValue(IsSelectedProperty, value); }
}
}
}
}

1
Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj

@ -91,6 +91,7 @@
<Compile Include="ContentPresenterTests.cs" />
<Compile Include="BorderTests.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Mixins\SelectableMixinTests.cs" />
<Compile Include="Parsers\GridLengthsParserTests.cs" />
<Compile Include="PopupTests.cs" />
<Compile Include="DropDownTests.cs" />

Loading…
Cancel
Save