diff --git a/Perspex.UnitTests/PerspexObjectTests.cs b/Perspex.UnitTests/PerspexObjectTests.cs index e8b5c26d43..51a9720062 100644 --- a/Perspex.UnitTests/PerspexObjectTests.cs +++ b/Perspex.UnitTests/PerspexObjectTests.cs @@ -161,6 +161,15 @@ namespace Perspex.UnitTests target.SetValue(Class2.BarProperty, "invalid"); } + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void SetValue_Throws_Exception_For_Invalid_Value_Type() + { + Class1 target = new Class1(); + + target.SetValue(Class1.FooProperty, 123); + } + [TestMethod] public void GetObservable_Returns_Initial_Value() { @@ -271,7 +280,7 @@ namespace Perspex.UnitTests } [TestMethod] - public void Binding_Sets_Current_Value() + public void Bind_Sets_Current_Value() { Class1 target = new Class1(); Class1 source = new Class1(); @@ -283,7 +292,7 @@ namespace Perspex.UnitTests } [TestMethod] - public void Binding_NonGeneric_Sets_Current_Value() + public void Bind_NonGeneric_Sets_Current_Value() { Class1 target = new Class1(); Class1 source = new Class1(); @@ -295,7 +304,7 @@ namespace Perspex.UnitTests } [TestMethod] - public void Binding_Sets_Subsequent_Value() + public void Bind_Sets_Subsequent_Value() { Class1 target = new Class1(); Class1 source = new Class1(); @@ -322,7 +331,7 @@ namespace Perspex.UnitTests } [TestMethod] - public void Binding_Doesnt_Set_Value_After_Reset() + public void Bind_Doesnt_Set_Value_After_Reset() { Class1 target = new Class1(); Class1 source = new Class1(); @@ -335,6 +344,15 @@ namespace Perspex.UnitTests Assert.AreEqual("reset", target.GetValue(Class1.FooProperty)); } + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void Bind_Throws_Exception_For_Invalid_Value_Type() + { + Class1 target = new Class1(); + + target.Bind((PerspexProperty)Class1.FooProperty, Observable.Return((object)123)); + } + [TestMethod] public void Setting_UnsetValue_Reverts_To_Default_Value() { diff --git a/Perspex.UnitTests/PriorityValueTEsts.cs b/Perspex.UnitTests/PriorityValueTEsts.cs index 90b7af28f1..742b9a0160 100644 --- a/Perspex.UnitTests/PriorityValueTEsts.cs +++ b/Perspex.UnitTests/PriorityValueTEsts.cs @@ -19,7 +19,7 @@ namespace Perspex.UnitTests [TestMethod] public void Initial_Value_Should_Be_UnsetValue() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); Assert.AreSame(PerspexProperty.UnsetValue, target.Value); } @@ -27,7 +27,7 @@ namespace Perspex.UnitTests [TestMethod] public void First_Binding_Sets_Value() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); target.Add(this.Single("foo"), 0); @@ -37,7 +37,7 @@ namespace Perspex.UnitTests [TestMethod] public void Changing_Binding_Should_Set_Value() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); var subject = new BehaviorSubject("foo"); target.Add(subject, 0); @@ -49,7 +49,7 @@ namespace Perspex.UnitTests [TestMethod] public void Binding_With_Lower_Priority_Has_Precedence() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); target.Add(this.Single("foo"), 1); target.Add(this.Single("bar"), 0); @@ -61,7 +61,7 @@ namespace Perspex.UnitTests [TestMethod] public void Later_Binding_With_Same_Priority_Should_Take_Precedence() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); target.Add(this.Single("foo"), 1); target.Add(this.Single("bar"), 0); @@ -74,7 +74,7 @@ namespace Perspex.UnitTests [TestMethod] public void Changing_Binding_With_Lower_Priority_Should_Set_Not_Value() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); var subject = new BehaviorSubject("bar"); target.Add(this.Single("foo"), 0); @@ -87,7 +87,7 @@ namespace Perspex.UnitTests [TestMethod] public void UnsetValue_Should_Fall_Back_To_Next_Binding() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); var subject = new BehaviorSubject("bar"); target.Add(subject, 0); @@ -103,7 +103,7 @@ namespace Perspex.UnitTests [TestMethod] public void Adding_Value_Should_Call_OnNext() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); bool called = false; target.Changed.Subscribe(value => called = (value.Item1 == PerspexProperty.UnsetValue && (string)value.Item2 == "foo")); @@ -115,7 +115,7 @@ namespace Perspex.UnitTests [TestMethod] public void Changing_Value_Should_Call_OnNext() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); var subject = new BehaviorSubject("foo"); bool called = false; @@ -129,7 +129,7 @@ namespace Perspex.UnitTests [TestMethod] public void Disposing_A_Binding_Should_Revert_To_Next_Value() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); target.Add(this.Single("foo"), 0); var disposable = target.Add(this.Single("bar"), 0); @@ -142,7 +142,7 @@ namespace Perspex.UnitTests [TestMethod] public void Disposing_A_Binding_Should_Remove_BindingEntry() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); target.Add(this.Single("foo"), 0); var disposable = target.Add(this.Single("bar"), 0); @@ -155,7 +155,7 @@ namespace Perspex.UnitTests [TestMethod] public void Completing_A_Binding_Should_Revert_To_Next_Value() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); var subject = new BehaviorSubject("bar"); target.Add(this.Single("foo"), 0); @@ -169,7 +169,7 @@ namespace Perspex.UnitTests [TestMethod] public void Completing_A_Binding_Should_Remove_BindingEntry() { - var target = new PriorityValue(); + var target = new PriorityValue("Test", typeof(string)); var subject = new BehaviorSubject("bar"); target.Add(this.Single("foo"), 0); diff --git a/Perspex/Controls/DataTemplate.cs b/Perspex/Controls/DataTemplate.cs index 23a925eb97..41efe6e254 100644 --- a/Perspex/Controls/DataTemplate.cs +++ b/Perspex/Controls/DataTemplate.cs @@ -20,7 +20,7 @@ namespace Perspex.Controls } public DataTemplate(Type type, Func build) - : this(o => type.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo()), build) + : this(o => IsInstance(o, type), build) { } @@ -33,6 +33,11 @@ namespace Perspex.Controls this.Build = build; } + public static bool IsInstance(object o, Type t) + { + return t.GetTypeInfo().IsAssignableFrom(o.GetType().GetTypeInfo()); + } + public Func Match { get; private set; } public Func Build { get; private set; } diff --git a/Perspex/Controls/HeaderedItemsControl.cs b/Perspex/Controls/HeaderedItemsControl.cs new file mode 100644 index 0000000000..d65d1635b4 --- /dev/null +++ b/Perspex/Controls/HeaderedItemsControl.cs @@ -0,0 +1,25 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using System; + using System.Collections; + using System.Linq; + using System.Reactive.Linq; + + public class HeaderedItemsControl : ItemsControl + { + public static readonly PerspexProperty HeaderProperty = + HeaderedContentControl.HeaderProperty.AddOwner(); + + public object Header + { + get { return this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + } +} diff --git a/Perspex/Controls/ItemsControl.cs b/Perspex/Controls/ItemsControl.cs index b233741ead..d3cb6eedf0 100644 --- a/Perspex/Controls/ItemsControl.cs +++ b/Perspex/Controls/ItemsControl.cs @@ -21,9 +21,6 @@ namespace Perspex.Controls public static readonly PerspexProperty ItemsPanelProperty = PerspexProperty.Register("ItemsPanel", defaultValue: DefaultPanel); - public static readonly PerspexProperty ItemTemplateProperty = - PerspexProperty.Register("ItemTemplate"); - private Dictionary itemControls = new Dictionary(); public IEnumerable Items @@ -38,12 +35,6 @@ namespace Perspex.Controls set { this.SetValue(ItemsPanelProperty, value); } } - public DataTemplate ItemTemplate - { - get { return this.GetValue(ItemTemplateProperty); } - set { this.SetValue(ItemTemplateProperty, value); } - } - public Control GetControlForItem(object item) { Control result; @@ -65,21 +56,7 @@ namespace Perspex.Controls protected virtual Control CreateItemControlOverride(object item) { - Control control = item as Control; - DataTemplate template = this.ItemTemplate; - - if (control != null) - { - return control; - } - else if (template != null) - { - return template.Build(item); - } - else - { - return this.GetDataTemplate(item).Build(item); - } + return (item as Control) ?? this.GetDataTemplate(item).Build(item); } } } diff --git a/Perspex/Controls/ItemsPresenter.cs b/Perspex/Controls/ItemsPresenter.cs index cb369c3bc3..78ef051459 100644 --- a/Perspex/Controls/ItemsPresenter.cs +++ b/Perspex/Controls/ItemsPresenter.cs @@ -20,9 +20,6 @@ namespace Perspex.Controls public static readonly PerspexProperty ItemsPanelProperty = ItemsControl.ItemsPanelProperty.AddOwner(); - public static readonly PerspexProperty ItemTemplateProperty = - ItemsControl.ItemTemplateProperty.AddOwner(); - private Panel panel; public ItemsPresenter() @@ -42,12 +39,6 @@ namespace Perspex.Controls set { this.SetValue(ItemsPanelProperty, value); } } - public DataTemplate ItemTemplate - { - get { return this.GetValue(ItemTemplateProperty); } - set { this.SetValue(ItemTemplateProperty, value); } - } - IEnumerable IVisual.ExistingVisualChildren { get { return Enumerable.Repeat(this.panel, this.panel != null ? 1 : 0); } diff --git a/Perspex/Controls/TabStrip.cs b/Perspex/Controls/TabStrip.cs index 67497a04da..6135a7352f 100644 --- a/Perspex/Controls/TabStrip.cs +++ b/Perspex/Controls/TabStrip.cs @@ -14,13 +14,9 @@ namespace Perspex.Controls private static readonly ItemsPanelTemplate PanelTemplate = new ItemsPanelTemplate( () => new StackPanel()); - private static readonly DataTemplate TabTemplate = new DataTemplate( - o => new TabItem { Content = o }); - static TabStrip() { ItemsPanelProperty.OverrideDefaultValue(typeof(TabStrip), PanelTemplate); - ItemTemplateProperty.OverrideDefaultValue(typeof(TabStrip), TabTemplate); } public TabStrip() @@ -37,7 +33,7 @@ namespace Perspex.Controls { result = new TabItem { - Content = item, + Content = this.GetDataTemplate(item).Build(item), }; } diff --git a/Perspex/Controls/TreeDataTemplate.cs b/Perspex/Controls/TreeDataTemplate.cs new file mode 100644 index 0000000000..c38754eb32 --- /dev/null +++ b/Perspex/Controls/TreeDataTemplate.cs @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using System; + using System.Collections; + + public class TreeDataTemplate : DataTemplate + { + public TreeDataTemplate( + Func build, + Func itemsSelector) + : this(o => true, build, itemsSelector) + { + } + + public TreeDataTemplate( + Type type, + Func build, + Func itemsSelector) + : this(o => IsInstance(o, type), build, itemsSelector) + { + } + + public TreeDataTemplate( + Func match, + Func build, + Func itemsSelector) + : base(match, build) + { + this.ItemsSelector = itemsSelector; + } + + public Func ItemsSelector { get; private set; } + } + + public class TreeDataTemplate : TreeDataTemplate + { + public TreeDataTemplate( + Func build, + Func itemsSelector) + : base(typeof(T), o => build((T)o), o => itemsSelector((T)o)) + { + } + + public TreeDataTemplate( + Func match, + Func build, + Func itemsSelector) + : base(o => (o is T) ? match((T)o) : false, o => build((T)o), o => itemsSelector((T)o)) + { + } + } +} diff --git a/Perspex/Controls/TreeView.cs b/Perspex/Controls/TreeView.cs new file mode 100644 index 0000000000..95bb5577ba --- /dev/null +++ b/Perspex/Controls/TreeView.cs @@ -0,0 +1,47 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using System; + using System.Collections; + using System.Linq; + using System.Reactive.Linq; + + public class TreeView : SelectingItemsControl + { + protected override Control CreateItemControlOverride(object item) + { + TreeViewItem result = item as TreeViewItem; + + if (result == null) + { + TreeDataTemplate template = this.GetTreeDataTemplate(item); + + result = new TreeViewItem + { + Header = template.Build(item), + Items = template.ItemsSelector(item), + }; + } + + return result; + } + + private TreeDataTemplate GetTreeDataTemplate(object item) + { + DataTemplate template = this.GetDataTemplate(item); + TreeDataTemplate treeTemplate = template as TreeDataTemplate; + + if (treeTemplate == null) + { + treeTemplate = new TreeDataTemplate(template.Build, x => null); + } + + return treeTemplate; + } + } +} diff --git a/Perspex/Controls/TreeViewItem.cs b/Perspex/Controls/TreeViewItem.cs new file mode 100644 index 0000000000..6c1a841c17 --- /dev/null +++ b/Perspex/Controls/TreeViewItem.cs @@ -0,0 +1,17 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using System; + using System.Collections; + using System.Linq; + using System.Reactive.Linq; + + public class TreeViewItem : HeaderedItemsControl + { + } +} diff --git a/Perspex/Perspex.csproj b/Perspex/Perspex.csproj index 80790baa14..b79c7989ad 100644 --- a/Perspex/Perspex.csproj +++ b/Perspex/Perspex.csproj @@ -70,9 +70,13 @@ + + + + @@ -135,6 +139,8 @@ + + diff --git a/Perspex/PerspexObject.cs b/Perspex/PerspexObject.cs index 972f88b858..774ba70320 100644 --- a/Perspex/PerspexObject.cs +++ b/Perspex/PerspexObject.cs @@ -43,6 +43,11 @@ namespace Perspex /// A style binding. /// Style, + + /// + /// The binding is uninitialized. + /// + Unset = int.MaxValue, } /// @@ -200,7 +205,7 @@ namespace Perspex } /// - /// Clears a value, including its binding. + /// Clears a 's local value. /// /// The property. public void ClearValue(PerspexProperty property) @@ -394,6 +399,15 @@ namespace Perspex this.GetType())); } + if (!PriorityValue.IsValidValue(value, property.PropertyType)) + { + throw new InvalidOperationException(string.Format( + "Invalid value for Property '{0}': {1} ({2})", + property.Name, + value, + value.GetType().FullName)); + } + if (!this.values.TryGetValue(property, out v)) { if (value == PerspexProperty.UnsetValue) @@ -493,7 +507,7 @@ namespace Perspex private PriorityValue CreatePriorityValue(PerspexProperty property) { - PriorityValue result = new PriorityValue(); + PriorityValue result = new PriorityValue(property.Name, property.PropertyType); result.Changed.Subscribe(x => { diff --git a/Perspex/PerspexProperty.cs b/Perspex/PerspexProperty.cs index 152b2cab01..f3db1f5a9d 100644 --- a/Perspex/PerspexProperty.cs +++ b/Perspex/PerspexProperty.cs @@ -25,7 +25,7 @@ namespace Perspex /// /// Represents an unset property value. /// - public static readonly object UnsetValue = new object(); + public static readonly object UnsetValue = new Unset(); /// /// The default values for the property, by type. @@ -259,6 +259,14 @@ namespace Perspex private set; } } + + private class Unset + { + public override string ToString() + { + return "{Unset}"; + } + } } /// diff --git a/Perspex/PriorityValue.cs b/Perspex/PriorityValue.cs index 9972b81d68..2ec892ca51 100644 --- a/Perspex/PriorityValue.cs +++ b/Perspex/PriorityValue.cs @@ -10,6 +10,7 @@ namespace Perspex using System.Collections.Generic; using System.Reactive.Disposables; using System.Reactive.Subjects; + using System.Reflection; /// /// Maintains a list of prioritised bindings together with a current value. @@ -25,6 +26,16 @@ namespace Perspex /// public class PriorityValue { + /// + /// The name of the property. + /// + private string name; + + /// + /// The value type. + /// + private Type valueType; + /// /// The currently registered binding entries. /// @@ -43,8 +54,12 @@ namespace Perspex /// /// Initializes a new instance of the class. /// - public PriorityValue() + /// The name of the property. + /// The value type. + public PriorityValue(string name, Type valueType) { + this.name = name; + this.valueType = valueType; this.value = PerspexProperty.UnsetValue; this.ValuePriority = int.MaxValue; } @@ -74,6 +89,39 @@ namespace Perspex private set; } + /// + /// Checks whether a value is valid for a type. + /// + /// + /// + /// + public static bool IsValidValue(object value, Type propertyType) + { + TypeInfo type = propertyType.GetTypeInfo(); + + if (value == PerspexProperty.UnsetValue) + { + return true; + } + else if (value == null) + { + if (type.IsValueType && + (!type.IsGenericType || !(type.GetGenericTypeDefinition() == typeof(Nullable<>)))) + { + return false; + } + } + else + { + if (!type.IsAssignableFrom(value.GetType().GetTypeInfo())) + { + return false; + } + } + + return true; + } + /// /// Adds a new binding. /// @@ -218,6 +266,15 @@ namespace Perspex /// The priority of the binding which produced the value. private void SetValue(object value, int priority) { + if (!IsValidValue(value, this.valueType)) + { + throw new InvalidOperationException(string.Format( + "Invalid value for Property '{0}': {1} ({2})", + this.name, + value, + value.GetType().FullName)); + } + object old = this.value; this.ValuePriority = priority; diff --git a/Perspex/Themes/Default/DefaultTheme.cs b/Perspex/Themes/Default/DefaultTheme.cs index edec40031a..e4f7f1ee5f 100644 --- a/Perspex/Themes/Default/DefaultTheme.cs +++ b/Perspex/Themes/Default/DefaultTheme.cs @@ -20,6 +20,8 @@ namespace Perspex.Themes.Default this.Add(new TabItemStyle()); this.Add(new TabStripStyle()); this.Add(new TextBoxStyle()); + this.Add(new TreeViewStyle()); + this.Add(new TreeViewItemStyle()); } } } diff --git a/Perspex/Themes/Default/ItemsControlStyle.cs b/Perspex/Themes/Default/ItemsControlStyle.cs index 7cdb01140a..396c6f7802 100644 --- a/Perspex/Themes/Default/ItemsControlStyle.cs +++ b/Perspex/Themes/Default/ItemsControlStyle.cs @@ -32,7 +32,6 @@ namespace Perspex.Themes.Default { [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], - [~ItemsPresenter.ItemTemplateProperty] = control[~ItemsControl.ItemTemplateProperty], }; } } diff --git a/Perspex/Themes/Default/TabStripStyle.cs b/Perspex/Themes/Default/TabStripStyle.cs index 40198c69ab..cea79f49ae 100644 --- a/Perspex/Themes/Default/TabStripStyle.cs +++ b/Perspex/Themes/Default/TabStripStyle.cs @@ -40,7 +40,6 @@ namespace Perspex.Themes.Default { [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty], [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], - [~ItemsPresenter.ItemTemplateProperty] = control[~ItemsControl.ItemTemplateProperty], }; } } diff --git a/Perspex/Themes/Default/TreeViewItemStyle.cs b/Perspex/Themes/Default/TreeViewItemStyle.cs new file mode 100644 index 0000000000..f912f92cfb --- /dev/null +++ b/Perspex/Themes/Default/TreeViewItemStyle.cs @@ -0,0 +1,49 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Themes.Default +{ + using System.Linq; + using Perspex.Controls; + using Perspex.Styling; + + public class TreeViewItemStyle : Styles + { + public TreeViewItemStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(Button.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + }); + } + + private Control Template(TreeViewItem control) + { + return new StackPanel + { + Children = new Controls + { + new ContentPresenter + { + [~ContentPresenter.ContentProperty] = control[~TreeViewItem.HeaderProperty], + }, + new ItemsPresenter + { + Margin = new Thickness(13, 0, 0, 0), + [~ItemsPresenter.ItemsProperty] = control[~TreeViewItem.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~TreeViewItem.ItemsPanelProperty], + } + } + }; + } + } +} diff --git a/Perspex/Themes/Default/TreeViewStyle.cs b/Perspex/Themes/Default/TreeViewStyle.cs new file mode 100644 index 0000000000..9d14627b09 --- /dev/null +++ b/Perspex/Themes/Default/TreeViewStyle.cs @@ -0,0 +1,38 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Themes.Default +{ + using System.Linq; + using Perspex.Controls; + using Perspex.Styling; + + public class TreeViewStyle : Styles + { + public TreeViewStyle() + { + this.AddRange(new[] + { + new Style(x => x.OfType()) + { + Setters = new[] + { + new Setter(Button.TemplateProperty, ControlTemplate.Create(this.Template)), + }, + }, + }); + } + + private Control Template(TreeView control) + { + return new ItemsPresenter + { + [~ItemsPresenter.ItemsProperty] = control[~TreeView.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~TreeView.ItemsPanelProperty], + }; + } + } +} diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index dc505d2a26..c259ff101a 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -1,4 +1,6 @@ -using Perspex; +using System.Collections; +using System.Collections.Generic; +using Perspex; using Perspex.Controls; using Perspex.Layout; using Perspex.Media; @@ -30,74 +32,146 @@ namespace TestApplication public string Value { get; set; } } + class Node + { + public string Name { get; set; } + public IEnumerable Children { get; set; } + } + class Program { - static void Main(string[] args) + private static Node[] treeData = new[] { - App application = new App(); + new Node + { + Name = "Root 1", + Children = new[] + { + new Node + { + Name = "Child 1", + }, + new Node + { + Name = "Child 2", + Children = new[] + { + new Node + { + Name = "Grandchild 1", + }, + new Node + { + Name = "Grandmaster Flash", + }, + } + }, + new Node + { + Name = "Child 3", + }, + } + }, + new Node + { + Name = "Root 2", + }, + }; + static void Main(string[] args) + { //Locator.CurrentMutable.Register(() => new TestLogger { Level = LogLevel.Debug } , typeof(ILogger)); + App application = new App + { + DataTemplates = new DataTemplates + { + new TreeDataTemplate( + x => new TextBlock { Text = x.ToString() }, + x => x.Children), + }, + }; + Window window = new Window { Content = new TabControl { Items = new[] { + //new TabItem + //{ + // Header = "Buttons", + // Content = new StackPanel + // { + // Orientation = Orientation.Vertical, + // HorizontalAlignment = HorizontalAlignment.Center, + // VerticalAlignment = VerticalAlignment.Center, + // Gap = 8, + // MinWidth = 120, + // Children = new Controls + // { + // new Button + // { + // Content = "Button", + // }, + // new Button + // { + // Content = "Button", + // Background = new SolidColorBrush(0xcc119eda), + // }, + // new CheckBox + // { + // Content = "Checkbox", + // }, + // } + // }, + //}, + //new TabItem + //{ + // Header = "Text", + // Content = new StackPanel + // { + // Orientation = Orientation.Vertical, + // HorizontalAlignment = HorizontalAlignment.Center, + // VerticalAlignment = VerticalAlignment.Center, + // Gap = 8, + // Width = 120, + // Children = new Controls + // { + // new TextBlock + // { + // Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.", + // }, + // new TextBox + // { + // Text = "Text Box", + // }, + // } + // }, + //}, + //new TabItem + //{ + // Header = "Images", + // Content = new StackPanel + // { + // Orientation = Orientation.Vertical, + // HorizontalAlignment = HorizontalAlignment.Center, + // VerticalAlignment = VerticalAlignment.Center, + // Gap = 8, + // Width = 120, + // Children = new Controls + // { + // new Image + // { + // Source = new Bitmap("github_icon.png"), + // Width = 200, + // }, + // } + // }, + //}, new TabItem { - Header = "Buttons", - Content = new StackPanel - { - Orientation = Orientation.Vertical, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Gap = 8, - MinWidth = 120, - Children = new Controls - { - new Button - { - Content = "Button", - }, - new Button - { - Content = "Button", - Background = new SolidColorBrush(0xcc119eda), - }, - new CheckBox - { - Content = "Checkbox", - }, - } - }, - }, - new TabItem - { - Header = "Text", - Content = new StackPanel - { - Orientation = Orientation.Vertical, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Gap = 8, - Width = 120, - Children = new Controls - { - new TextBlock - { - Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.", - }, - new TextBox - { - Text = "Text Box", - }, - } - }, - }, - new TabItem - { - Header = "Images", + Header = "Lists", Content = new StackPanel { Orientation = Orientation.Vertical, @@ -107,10 +181,9 @@ namespace TestApplication Width = 120, Children = new Controls { - new Image + new TreeView { - Source = new Bitmap("github_icon.png"), - Width = 200, + Items = treeData, }, } },