diff --git a/Perspex.Controls/CheckBox.cs b/Perspex.Controls/CheckBox.cs index eb16656037..f4231f3497 100644 --- a/Perspex.Controls/CheckBox.cs +++ b/Perspex.Controls/CheckBox.cs @@ -4,10 +4,10 @@ // // ----------------------------------------------------------------------- -using Perspex.Controls.Primitives; - namespace Perspex.Controls { + using Perspex.Controls.Primitives; + public class CheckBox : ToggleButton { } diff --git a/Perspex.Controls/ISelectable.cs b/Perspex.Controls/ISelectable.cs new file mode 100644 index 0000000000..dae37394fa --- /dev/null +++ b/Perspex.Controls/ISelectable.cs @@ -0,0 +1,13 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + public interface ISelectable + { + bool IsSelected { get; set; } + } +} diff --git a/Perspex.Controls/ListBox.cs b/Perspex.Controls/ListBox.cs new file mode 100644 index 0000000000..2a98e7bf56 --- /dev/null +++ b/Perspex.Controls/ListBox.cs @@ -0,0 +1,19 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using Perspex.Controls.Generators; + using Perspex.Controls.Primitives; + + public class ListBox : SelectingItemsControl + { + protected override ItemContainerGenerator CreateItemContainerGenerator() + { + return new TypedItemContainerGenerator(this); + } + } +} diff --git a/Perspex.Controls/ListBoxItem.cs b/Perspex.Controls/ListBoxItem.cs new file mode 100644 index 0000000000..327cff7887 --- /dev/null +++ b/Perspex.Controls/ListBoxItem.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + public class ListBoxItem : ContentControl, ISelectable + { + public static readonly PerspexProperty IsSelectedProperty = + PerspexProperty.Register("IsSelected"); + + static ListBoxItem() + { + PseudoClass(IsSelectedProperty, ":selected"); + } + + public bool IsSelected + { + get { return this.GetValue(IsSelectedProperty); } + set { this.SetValue(IsSelectedProperty, value); } + } + } +} diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index 221f2731c3..7d903d4afb 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -41,6 +41,9 @@ + + + diff --git a/Perspex.Controls/Primitives/SelectingItemsControl.cs b/Perspex.Controls/Primitives/SelectingItemsControl.cs index e63278cea5..e53b993bcf 100644 --- a/Perspex.Controls/Primitives/SelectingItemsControl.cs +++ b/Perspex.Controls/Primitives/SelectingItemsControl.cs @@ -6,15 +6,68 @@ namespace Perspex.Controls.Primitives { + using System; + using System.Linq; + using Perspex.Controls.Presenters; + using Perspex.Input; + using Perspex.Interactivity; + public class SelectingItemsControl : ItemsControl { public static readonly PerspexProperty SelectedItemProperty = PerspexProperty.Register("SelectedItem"); + static SelectingItemsControl() + { + SelectedItemProperty.Changed.Subscribe(x => + { + var control = x.Sender as SelectingItemsControl; + + if (control != null) + { + control.SelectedItemChanged(x.NewValue); + } + }); + } + public object SelectedItem { get { return this.GetValue(SelectedItemProperty); } set { this.SetValue(SelectedItemProperty, value); } } + + protected override void OnPointerPressed(PointerEventArgs e) + { + IVisual source = (IVisual)e.Source; + var selectable = source.GetVisualAncestors() + .OfType() + .OfType() + .FirstOrDefault(); + + if (selectable != null) + { + var container = this.ItemContainerGenerator.GetItemForContainer(selectable); + + if (container != null) + { + this.SelectedItem = container; + } + } + } + + private void SelectedItemChanged(object selected) + { + var containers = this.ItemContainerGenerator.GetAll() + .Select(x => x.Item2) + .OfType(); + var selectedContainer = (selected != null) ? + this.ItemContainerGenerator.GetContainerForItem(selected) : + null; + + foreach (var item in containers) + { + item.IsSelected = item == selectedContainer; + } + } } } diff --git a/Perspex.Controls/Primitives/TabStrip.cs b/Perspex.Controls/Primitives/TabStrip.cs index 3c0b197a37..0f6cc6a2f9 100644 --- a/Perspex.Controls/Primitives/TabStrip.cs +++ b/Perspex.Controls/Primitives/TabStrip.cs @@ -23,12 +23,6 @@ namespace Perspex.Controls.Primitives ItemsPanelProperty.OverrideDefaultValue(typeof(TabStrip), PanelTemplate); } - public TabStrip() - { - this.PointerPressed += this.OnPointerPressed; - this.GetObservable(SelectedItemProperty).Subscribe(this.SelectedItemChanged); - } - protected override ItemContainerGenerator CreateItemContainerGenerator() { TabControl tabControl = this.TemplatedParent as TabControl; @@ -60,31 +54,5 @@ namespace Perspex.Controls.Primitives this.SelectedItem = tabs.FirstOrDefault(x => x.IsSelected) ?? tabs.FirstOrDefault(); } } - - private void OnPointerPressed(object sender, PointerEventArgs e) - { - IVisual source = (IVisual)e.Source; - ContentPresenter presenter = source.GetVisualAncestors() - .OfType() - .FirstOrDefault(); - - if (presenter != null) - { - TabItem item = presenter.TemplatedParent as TabItem; - - if (item != null) - { - this.SelectedItem = item; - } - } - } - - private void SelectedItemChanged(object selected) - { - foreach (TabItem item in this.ItemContainerGenerator.GetAll().Select(x => x.Item2)) - { - item.IsSelected = selected == item; - } - } } } diff --git a/Perspex.Controls/TabItem.cs b/Perspex.Controls/TabItem.cs index 0506c9fdd3..3f2fca5757 100644 --- a/Perspex.Controls/TabItem.cs +++ b/Perspex.Controls/TabItem.cs @@ -8,10 +8,10 @@ namespace Perspex.Controls { using Perspex.Controls.Primitives; - public class TabItem : HeaderedContentControl + public class TabItem : HeaderedContentControl, ISelectable { public static readonly PerspexProperty IsSelectedProperty = - PerspexProperty.Register("IsSelected"); + ListBoxItem.IsSelectedProperty.AddOwner(); static TabItem() { diff --git a/Perspex.Controls/TreeView.cs b/Perspex.Controls/TreeView.cs index 79c298c110..85ead34278 100644 --- a/Perspex.Controls/TreeView.cs +++ b/Perspex.Controls/TreeView.cs @@ -15,38 +15,33 @@ namespace Perspex.Controls public class TreeView : SelectingItemsControl { - public TreeView() - { - this.PointerPressed += this.OnPointerPressed; - } - protected override ItemContainerGenerator CreateItemContainerGenerator() { return new TreeItemContainerGenerator(this); } - private void OnPointerPressed(object sender, PointerEventArgs e) - { - IVisual source = (IVisual)e.Source; - ContentPresenter contentPresenter = source.GetVisualAncestors() - .OfType() - .FirstOrDefault(); - - if (contentPresenter != null) - { - TreeViewItem container = contentPresenter.TemplatedParent as TreeViewItem; - - if (container != null) - { - foreach (var i in this.GetVisualDescendents().OfType()) - { - i.IsSelected = i == container; - } - - this.SelectedItem = this.ItemContainerGenerator.GetItemForContainer(container); - } - } - - } + //protected override void OnPointerPressed(PointerEventArgs e) + //{ + // IVisual source = (IVisual)e.Source; + // ContentPresenter contentPresenter = source.GetVisualAncestors() + // .OfType() + // .FirstOrDefault(); + + // if (contentPresenter != null) + // { + // TreeViewItem container = contentPresenter.TemplatedParent as TreeViewItem; + + // if (container != null) + // { + // foreach (var i in this.GetVisualDescendents().OfType()) + // { + // i.IsSelected = i == container; + // } + + // this.SelectedItem = this.ItemContainerGenerator.GetItemForContainer(container); + // } + // } + + //} } } diff --git a/Perspex.Controls/TreeViewItem.cs b/Perspex.Controls/TreeViewItem.cs index 2a373e4663..8b24db205c 100644 --- a/Perspex.Controls/TreeViewItem.cs +++ b/Perspex.Controls/TreeViewItem.cs @@ -11,13 +11,13 @@ namespace Perspex.Controls using Perspex.Controls.Generators; using Perspex.Controls.Primitives; - public class TreeViewItem : HeaderedItemsControl + public class TreeViewItem : HeaderedItemsControl, ISelectable { public static readonly PerspexProperty IsExpandedProperty = PerspexProperty.Register("IsExpanded"); public static readonly PerspexProperty IsSelectedProperty = - PerspexProperty.Register("IsSelected"); + ListBoxItem.IsSelectedProperty.AddOwner(); TreeView treeView; diff --git a/Perspex.Themes.Default/DefaultTheme.cs b/Perspex.Themes.Default/DefaultTheme.cs index 0a184873ab..5928731e02 100644 --- a/Perspex.Themes.Default/DefaultTheme.cs +++ b/Perspex.Themes.Default/DefaultTheme.cs @@ -17,6 +17,8 @@ namespace Perspex.Themes.Default this.Add(new ContentControlStyle()); this.Add(new GridSplitterStyle()); this.Add(new ItemsControlStyle()); + this.Add(new ListBoxStyle()); + this.Add(new ListBoxItemStyle()); this.Add(new ScrollBarStyle()); this.Add(new ScrollViewerStyle()); this.Add(new TabControlStyle()); diff --git a/Perspex.Themes.Default/ListBoxItemStyle.cs b/Perspex.Themes.Default/ListBoxItemStyle.cs new file mode 100644 index 0000000000..974b455e86 --- /dev/null +++ b/Perspex.Themes.Default/ListBoxItemStyle.cs @@ -0,0 +1,57 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Themes.Default +{ + using System.Linq; + using Perspex.Controls; + using Perspex.Layout; + using Perspex.Media; + using Perspex.Controls.Shapes; + using Perspex.Styling; + using Perspex.Controls.Presenters; + using Perspex.Controls.Primitives; + + public class ListBoxItemStyle : Styles + { + public ListBoxItemStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(ListBoxItem.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + new Style(x => x.OfType().Class(":selected").Template().Id("border")) + { + Setters = new[] + { + new Setter(ListBoxItem.BackgroundProperty, new SolidColorBrush(0xff086f9e)), + new Setter(ListBoxItem.ForegroundProperty, Brushes.White), + }, + }, + }); + } + + private Control Template(ListBoxItem control) + { + return new Border + { + Id = "border", + [~Border.BackgroundProperty] = control[~ListBoxItem.BackgroundProperty], + [~Border.BorderBrushProperty] = control[~ListBoxItem.BorderBrushProperty], + [~Border.BorderThicknessProperty] = control[~ListBoxItem.BorderThicknessProperty], + Content = new ContentPresenter + { + [~ContentPresenter.ContentProperty] = control[~ListBoxItem.ContentProperty], + }, + }; + } + } +} diff --git a/Perspex.Themes.Default/ListBoxStyle.cs b/Perspex.Themes.Default/ListBoxStyle.cs new file mode 100644 index 0000000000..df2698b4d4 --- /dev/null +++ b/Perspex.Themes.Default/ListBoxStyle.cs @@ -0,0 +1,52 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Themes.Default +{ + using System.Linq; + using Perspex.Controls; + using Perspex.Controls.Presenters; + using Perspex.Media; + using Perspex.Styling; + + public class ListBoxStyle : Styles + { + public ListBoxStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(ListBox.TemplateProperty, ControlTemplate.Create(this.Template)), + new Setter(ListBox.BorderBrushProperty, Brushes.Black), + new Setter(ListBox.BorderThicknessProperty, 1.0), + }, + }, + }); + } + + private Control Template(ListBox control) + { + return new Border + { + Padding = new Thickness(4), + [~Border.BackgroundProperty] = control[~ListBox.BackgroundProperty], + [~Border.BorderBrushProperty] = control[~ListBox.BorderBrushProperty], + [~Border.BorderThicknessProperty] = control[~ListBox.BorderThicknessProperty], + Content = new ScrollViewer + { + Content = new ItemsPresenter + { + [~ItemsPresenter.ItemsProperty] = control[~ListBox.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~ListBox.ItemsPanelProperty], + } + } + }; + } + } +} diff --git a/Perspex.Themes.Default/Perspex.Themes.Default.csproj b/Perspex.Themes.Default/Perspex.Themes.Default.csproj index abb1b7a2b0..66ccce37e1 100644 --- a/Perspex.Themes.Default/Perspex.Themes.Default.csproj +++ b/Perspex.Themes.Default/Perspex.Themes.Default.csproj @@ -66,6 +66,8 @@ + + diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index b03021aa9d..47f71077ce 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -87,6 +87,13 @@ namespace TestApplication }, }; + private static PerspexList listBoxData = new PerspexList + { + new Item { Name = "Item 1", Value = "Item 1 Value" }, + new Item { Name = "Item 2", Value = "Item 2 Value" }, + new Item { Name = "Item 3", Value = "Item 3 Value" }, + }; + static void Main(string[] args) { //LogManager.Enable(new TestLogger()); @@ -264,6 +271,22 @@ namespace TestApplication Id = "treeView", Items = treeData, }, + new ListBox + { + DataTemplates = new DataTemplates + { + new DataTemplate(x => + new StackPanel + { + Children = new Controls + { + new TextBlock { Text = x.Name, FontSize = 24 }, + new TextBlock { Text = x.Value }, + } + }) + }, + Items = listBoxData, + } } }, };