From ced25df0677a5bf230a3e1d80d8c977625561df9 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 19 Sep 2014 15:45:37 +0200 Subject: [PATCH] WIP --- Perspex.Controls/ColumnDefinition.cs | 5 ++ Perspex.Controls/Control.cs | 24 +++++---- Perspex.Controls/ItemsControl.cs | 2 +- Perspex.Controls/ItemsPresenter.cs | 2 +- Perspex.Controls/Panel.cs | 35 +++++++++++- Perspex.Controls/TabStrip.cs | 2 +- Perspex.Controls/TreeView.cs | 8 ++- Perspex.Diagnostics/DevTools.cs | 47 ++++++++++++++++ .../Perspex.Diagnostics.csproj | 1 + Perspex.Input/InputElement.cs | 54 +++++++++++++++++-- Perspex.SceneGraph/Visual.cs | 12 +++++ Perspex.Windows/Perspex.Windows.csproj | 4 ++ Perspex.Windows/Window.cs | 17 ++++++ TestApplication/Program.cs | 29 +++++----- 14 files changed, 207 insertions(+), 35 deletions(-) create mode 100644 Perspex.Diagnostics/DevTools.cs diff --git a/Perspex.Controls/ColumnDefinition.cs b/Perspex.Controls/ColumnDefinition.cs index a07d2d45e2..3d8f2d5527 100644 --- a/Perspex.Controls/ColumnDefinition.cs +++ b/Perspex.Controls/ColumnDefinition.cs @@ -21,6 +21,11 @@ namespace Perspex.Controls { } + public ColumnDefinition(double value, GridUnitType type) + { + this.Width = new GridLength(value, type); + } + public ColumnDefinition(GridLength width) { this.Width = width; diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs index 53164ac817..3962ff12f9 100644 --- a/Perspex.Controls/Control.cs +++ b/Perspex.Controls/Control.cs @@ -203,13 +203,6 @@ namespace Perspex.Controls protected virtual DataTemplate FindDataTemplate(object content) { - Control control = content as Control; - - if (control != null) - { - return new DataTemplate(x => control); - } - // TODO: This needs to traverse the logical tree, not the visual. foreach (var i in this.GetVisualAncestors().OfType()) { @@ -238,9 +231,22 @@ namespace Perspex.Controls return null; } - protected DataTemplate GetDataTemplate(object content) + protected Control ApplyDataTemplate(object content) { - return this.FindDataTemplate(content) ?? DataTemplate.Default; + DataTemplate result = this.FindDataTemplate(content); + + if (result != null) + { + return result.Build(content); + } + else if (content is Control) + { + return (Control)content; + } + else + { + return DataTemplate.Default.Build(content); + } } } } diff --git a/Perspex.Controls/ItemsControl.cs b/Perspex.Controls/ItemsControl.cs index 7b26728be9..f097e58d09 100644 --- a/Perspex.Controls/ItemsControl.cs +++ b/Perspex.Controls/ItemsControl.cs @@ -90,7 +90,7 @@ namespace Perspex.Controls protected virtual Control CreateItemControlOverride(object item) { - return (item as Control) ?? this.GetDataTemplate(item).Build(item); + return this.ApplyDataTemplate(item); } private void ItemsChanged(Tuple value) diff --git a/Perspex.Controls/ItemsPresenter.cs b/Perspex.Controls/ItemsPresenter.cs index faa96da34b..64bd0af37f 100644 --- a/Perspex.Controls/ItemsPresenter.cs +++ b/Perspex.Controls/ItemsPresenter.cs @@ -68,7 +68,7 @@ namespace Perspex.Controls } else { - return this.GetDataTemplate(item).Build(item) as Control; + return this.ApplyDataTemplate(item); } } diff --git a/Perspex.Controls/Panel.cs b/Perspex.Controls/Panel.cs index 56bb01e896..a69887e425 100644 --- a/Perspex.Controls/Panel.cs +++ b/Perspex.Controls/Panel.cs @@ -7,7 +7,7 @@ namespace Perspex.Controls { using System; - using System.Collections.Generic; + using System.Collections.Specialized; using System.Linq; /// @@ -24,6 +24,7 @@ namespace Perspex.Controls if (this.children == null) { this.children = new Controls(); + this.children.CollectionChanged += ChildrenChanged; } return this.children; @@ -35,11 +36,41 @@ namespace Perspex.Controls if (this.children != value) { + if (this.children != null) + { + this.children.CollectionChanged -= ChildrenChanged; + } + this.children = value; this.ClearVisualChildren(); - this.AddVisualChildren(value); + + if (this.children != null) + { + this.children.CollectionChanged += ChildrenChanged; + this.AddVisualChildren(value); + } } } } + + private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) + { + // TODO: Handle Move and Replace. + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + this.AddVisualChildren(e.NewItems.OfType()); + break; + + case NotifyCollectionChangedAction.Remove: + this.RemoveVisualChildren(e.OldItems.OfType()); + break; + + case NotifyCollectionChangedAction.Reset: + this.ClearVisualChildren(); + this.AddVisualChildren(this.children); + break; + } + } } } diff --git a/Perspex.Controls/TabStrip.cs b/Perspex.Controls/TabStrip.cs index 4935f4114f..5fc95f73a8 100644 --- a/Perspex.Controls/TabStrip.cs +++ b/Perspex.Controls/TabStrip.cs @@ -36,7 +36,7 @@ namespace Perspex.Controls { result = new TabItem { - Content = this.GetDataTemplate(item).Build(item), + Content = this.ApplyDataTemplate(item), }; } diff --git a/Perspex.Controls/TreeView.cs b/Perspex.Controls/TreeView.cs index 9f2ad51838..88665602e9 100644 --- a/Perspex.Controls/TreeView.cs +++ b/Perspex.Controls/TreeView.cs @@ -40,7 +40,13 @@ namespace Perspex.Controls private TreeDataTemplate GetTreeDataTemplate(object item) { - DataTemplate template = this.GetDataTemplate(item); + DataTemplate template = this.FindDataTemplate(item); + + if (template == null) + { + template = DataTemplate.Default; + } + TreeDataTemplate treeTemplate = template as TreeDataTemplate; if (treeTemplate == null) diff --git a/Perspex.Diagnostics/DevTools.cs b/Perspex.Diagnostics/DevTools.cs new file mode 100644 index 0000000000..084d4ee9ad --- /dev/null +++ b/Perspex.Diagnostics/DevTools.cs @@ -0,0 +1,47 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Diagnostics +{ + using Perspex.Controls; + + public class DevTools : Decorator + { + public static readonly PerspexProperty RootProperty = + PerspexProperty.Register("Root"); + + public DevTools() + { + this.Content = new Grid + { + ColumnDefinitions = new ColumnDefinitions + { + new ColumnDefinition(1, GridUnitType.Star), + new ColumnDefinition(3, GridUnitType.Star), + }, + Children = new Controls + { + new TreeView + { + DataTemplates = new DataTemplates + { + new TreeDataTemplate( + x => new TextBlock {Text = x.GetType().Name }, + x => x.VisualChildren), + }, + [TreeView.ItemsProperty] = this[DevTools.RootProperty], + } + } + }; + } + + public Control Root + { + get { return this.GetValue(RootProperty); } + set { this.SetValue(RootProperty, value); } + } + } +} diff --git a/Perspex.Diagnostics/Perspex.Diagnostics.csproj b/Perspex.Diagnostics/Perspex.Diagnostics.csproj index b1cb4381ca..6643c9fb1c 100644 --- a/Perspex.Diagnostics/Perspex.Diagnostics.csproj +++ b/Perspex.Diagnostics/Perspex.Diagnostics.csproj @@ -65,6 +65,7 @@ + diff --git a/Perspex.Input/InputElement.cs b/Perspex.Input/InputElement.cs index 34a6d36b1d..0fda582268 100644 --- a/Perspex.Input/InputElement.cs +++ b/Perspex.Input/InputElement.cs @@ -47,10 +47,14 @@ namespace Perspex.Input public InputElement() { - this.GotFocus += (s, e) => this.IsFocused = true; - this.LostFocus += (s, e) => this.IsFocused = false; - this.PointerEnter += (s, e) => this.IsPointerOver = true; - this.PointerLeave += (s, e) => this.IsPointerOver = false; + this.GotFocus += (_, e) => this.OnGotFocus(e); + this.LostFocus += (_, e) => this.OnLostFocus(e); + this.KeyDown += (_, e) => this.OnKeyDown(e); + this.PreviewKeyDown += (_, e) => this.OnPreviewKeyDown(e); + this.PointerEnter += (_, e) => this.OnPointerEnter(e); + this.PointerLeave += (_, e) => this.OnPointerLeave(e); + this.PointerPressed += (_, e) => this.OnPointerPressed(e); + this.PointerReleased += (_, e) => this.OnPointerReleased(e); } public event EventHandler GotFocus @@ -71,6 +75,12 @@ namespace Perspex.Input remove { this.RemoveHandler(KeyDownEvent, value); } } + public event EventHandler PreviewKeyDown + { + add { this.AddHandler(PreviewKeyDownEvent, value); } + remove { this.RemoveHandler(PreviewKeyDownEvent, value); } + } + public event EventHandler PointerEnter { add { this.AddHandler(PointerEnterEvent, value); } @@ -117,5 +127,41 @@ namespace Perspex.Input { Locator.Current.GetService().Focus(this); } + + protected virtual void OnGotFocus(RoutedEventArgs e) + { + this.IsFocused = true; + } + + protected virtual void OnLostFocus(RoutedEventArgs e) + { + this.IsFocused = false; + } + + protected virtual void OnKeyDown(KeyEventArgs e) + { + } + + protected virtual void OnPreviewKeyDown(KeyEventArgs e) + { + } + + protected virtual void OnPointerEnter(PointerEventArgs e) + { + this.IsPointerOver = true; + } + + protected virtual void OnPointerLeave(PointerEventArgs e) + { + this.IsPointerOver = false; + } + + protected virtual void OnPointerPressed(PointerEventArgs e) + { + } + + protected virtual void OnPointerReleased(PointerEventArgs e) + { + } } } diff --git a/Perspex.SceneGraph/Visual.cs b/Perspex.SceneGraph/Visual.cs index 533ef69ecc..16101bf646 100644 --- a/Perspex.SceneGraph/Visual.cs +++ b/Perspex.SceneGraph/Visual.cs @@ -143,6 +143,18 @@ namespace Perspex this.visualChildren.Remove(visual); } + protected void RemoveVisualChildren(IEnumerable visuals) + { + Contract.Requires(visuals != null); + + this.EnsureVisualChildrenCreated(); + + foreach (var v in visuals) + { + this.visualChildren.Remove(v); + } + } + protected void SetVisualBounds(Rect bounds) { this.bounds = bounds; diff --git a/Perspex.Windows/Perspex.Windows.csproj b/Perspex.Windows/Perspex.Windows.csproj index 39175e85bf..cc9a4ec5ae 100644 --- a/Perspex.Windows/Perspex.Windows.csproj +++ b/Perspex.Windows/Perspex.Windows.csproj @@ -78,6 +78,10 @@ {d2221c82-4a25-4583-9b43-d791e3f6820c} Perspex.Controls + + {7062ae20-5dcc-4442-9645-8195bdece63e} + Perspex.Diagnostics + {62024b2d-53eb-4638-b26b-85eeaa54866e} Perspex.Input diff --git a/Perspex.Windows/Window.cs b/Perspex.Windows/Window.cs index f2b8fcfcd5..a3c1aeb4db 100644 --- a/Perspex.Windows/Window.cs +++ b/Perspex.Windows/Window.cs @@ -12,6 +12,7 @@ namespace Perspex.Windows using System.Reactive.Linq; using System.Runtime.InteropServices; using Perspex.Controls; + using Perspex.Diagnostics; using Perspex.Input; using Perspex.Input.Raw; using Perspex.Layout; @@ -114,6 +115,22 @@ namespace Perspex.Windows UnmanagedMethods.ShowWindow(this.Handle, 4); } + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + if (e.Key == Key.F12) + { + Window window = new Window + { + Content = new DevTools + { + Root = this, + }, + }; + + window.Show(); + } + } + private Control DefaultTemplate(Window c) { Border border = new Border(); diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index d4bf86947f..d738dff190 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -179,7 +179,6 @@ namespace TestApplication new TabItem { Header = "Lists", - IsSelected = true, Content = new StackPanel { Orientation = Orientation.Horizontal, @@ -218,22 +217,20 @@ namespace TestApplication } }; - System.Console.Write(Perspex.Diagnostics.Debug.PrintVisualTree(window)); + //var treeView = window.FindControl("treeView"); + //var newTreeViewItemText = window.FindControl("newTreeViewItemText"); + //var addTreeViewItem = window.FindControl