Browse Source

Started updating DevTools to use XAML.

pull/403/head
Steven Kirk 10 years ago
parent
commit
5773704f2d
  1. 12
      samples/ControlCatalog/App.paml.cs
  2. 9
      samples/ControlCatalog/ControlCatalog.csproj
  3. 4
      samples/ControlCatalog/packages.config
  4. 9
      src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs
  5. 17
      src/Perspex.Base/PriorityValue.cs
  6. 2
      src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs
  7. 120
      src/Perspex.Diagnostics/DevTools.cs
  8. 17
      src/Perspex.Diagnostics/DevTools.paml
  9. 52
      src/Perspex.Diagnostics/DevTools.paml.cs
  10. 27
      src/Perspex.Diagnostics/Perspex.Diagnostics.csproj
  11. 2
      src/Perspex.Diagnostics/ViewLocator.cs
  12. 57
      src/Perspex.Diagnostics/ViewModels/DevToolsViewModel.cs
  13. 34
      src/Perspex.Diagnostics/ViewModels/LogicalTreeViewModel.cs
  14. 7
      src/Perspex.Diagnostics/ViewModels/TreeNode.cs
  15. 13
      src/Perspex.Diagnostics/ViewModels/TreePageViewModel.cs
  16. 99
      src/Perspex.Diagnostics/Views/LogicalTreeView.cs
  17. 18
      src/Perspex.Diagnostics/Views/TreePage.paml.cs
  18. 24
      src/Perspex.Diagnostics/Views/TreePageView.paml
  19. 101
      src/Perspex.Diagnostics/Views/VisualTreeView.cs

12
samples/ControlCatalog/App.paml.cs

@ -5,6 +5,7 @@ using Perspex.Controls;
using Perspex.Diagnostics;
using Perspex.Markup.Xaml;
using Perspex.Themes.Default;
using Serilog;
namespace ControlCatalog
{
@ -14,6 +15,7 @@ namespace ControlCatalog
{
RegisterServices();
InitializeSubsystems(GetPlatformId());
InitializeLogging();
Styles = new DefaultTheme();
InitializeComponent();
}
@ -38,6 +40,16 @@ namespace ControlCatalog
PerspexXamlLoader.Load(this);
}
private void InitializeLogging()
{
#if DEBUG
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Error()
.WriteTo.Trace(outputTemplate: "{Message}")
.CreateLogger();
#endif
}
private int GetPlatformId()
{
var args = Environment.GetCommandLineArgs();

9
samples/ControlCatalog/ControlCatalog.csproj

@ -36,6 +36,14 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="Serilog, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Serilog.FullNetFx, Version=1.5.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.1.5.9\lib\net45\Serilog.FullNetFx.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@ -93,6 +101,7 @@
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\DropDownPage.paml" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Gtk\Perspex.Cairo\Perspex.Cairo.csproj">

4
samples/ControlCatalog/packages.config

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Serilog" version="1.5.9" targetFramework="net46" />
</packages>

9
src/Markup/Perspex.Markup.Xaml/Templates/TreeDataTemplate.cs

@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Reactive.Linq;
using System.Reflection;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Data;
@ -27,10 +28,12 @@ namespace Perspex.Markup.Xaml.Templates
{
if (DataType == null)
{
throw new InvalidOperationException("DataTemplate must have a DataType.");
return true;
}
else
{
return DataType.GetTypeInfo().IsAssignableFrom(data.GetType().GetTypeInfo());
}
return DataType == data.GetType();
}
public IEnumerable ItemsSelector(object item)

17
src/Perspex.Base/PriorityValue.cs

@ -224,26 +224,29 @@ namespace Perspex
/// <param name="priority">The priority level that the value came from.</param>
private void UpdateValue(object value, int priority)
{
if (TypeUtilities.TryCast(_valueType, value, out value))
object castValue;
if (TypeUtilities.TryCast(_valueType, value, out castValue))
{
var old = _value;
if (_validate != null && value != PerspexProperty.UnsetValue)
if (_validate != null && castValue != PerspexProperty.UnsetValue)
{
value = _validate(value);
castValue = _validate(castValue);
}
ValuePriority = priority;
_value = value;
_value = castValue;
_changed.OnNext(Tuple.Create(old, _value));
}
else if (_logger != null)
{
_logger.Error(
"Binding produced invalid value for {$Type} {$Property}: {$Value}",
_valueType,
"Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
_name,
value);
_valueType,
value,
value.GetType());
}
}

2
src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs

@ -77,7 +77,7 @@ namespace Perspex.Controls.Generators
result.SetValue(ContentProperty, template.Build(item));
result.SetValue(ItemsProperty, template.ItemsSelector(item));
result.SetValue(IsExpandedProperty, template.IsExpanded(item));
//result.SetValue(IsExpandedProperty, template.IsExpanded(item));
if (!(item is IControl))
{

120
src/Perspex.Diagnostics/DevTools.cs

@ -1,120 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Linq;
using Perspex.Controls;
using Perspex.Diagnostics.ViewModels;
using Perspex.Input;
using Perspex.Themes.Default;
using ReactiveUI;
namespace Perspex.Diagnostics
{
public class DevTools : Decorator
{
public static readonly PerspexProperty<Control> RootProperty =
PerspexProperty.Register<DevTools, Control>("Root");
private readonly DevToolsViewModel _viewModel;
public DevTools()
{
_viewModel = new DevToolsViewModel();
this.GetObservable(RootProperty).Subscribe(x => _viewModel.Root = x);
InitializeComponent();
}
public Control Root
{
get { return GetValue(RootProperty); }
set { SetValue(RootProperty, value); }
}
public static IDisposable Attach(Window window)
{
return window.AddHandler(
KeyDownEvent,
WindowPreviewKeyDown,
Interactivity.RoutingStrategies.Tunnel);
}
private static void WindowPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F12)
{
Window window = new Window
{
Width = 1024,
Height = 512,
Content = new DevTools
{
Root = (Window)sender,
},
};
window.Show();
}
}
private void InitializeComponent()
{
DataTemplates.Add(new ViewLocator<ReactiveObject>());
Styles.Add(new DefaultTheme());
Child = new Grid
{
RowDefinitions = new RowDefinitions("*,Auto"),
Children = new Controls.Controls
{
new TabControl
{
Items = new[]
{
new TabItem
{
Header = "Logical Tree",
[!ContentControl.ContentProperty] = _viewModel.WhenAnyValue(x => x.LogicalTree),
},
new TabItem
{
Header = "Visual Tree",
[!ContentControl.ContentProperty] = _viewModel.WhenAnyValue(x => x.VisualTree),
}
},
},
new StackPanel
{
Orientation = Orientation.Horizontal,
Gap = 4,
[Grid.RowProperty] = 1,
Children = new Controls.Controls
{
new TextBlock
{
Text = "Focused: "
},
new TextBlock
{
[!TextBlock.TextProperty] = _viewModel
.WhenAnyValue(x => x.FocusedControl)
.Select(x => x?.GetType().Name ?? "(null)")
},
new TextBlock
{
Text = "Pointer Over: "
},
new TextBlock
{
[!TextBlock.TextProperty] = _viewModel
.WhenAnyValue(x => x.PointerOverElement)
.Select(x => x?.GetType().Name ?? "(null)")
}
}
}
}
};
}
}
}

17
src/Perspex.Diagnostics/DevTools.paml

@ -0,0 +1,17 @@
<UserControl xmlns="https://github.com/perspex">
<Grid RowDefinitions="Auto,*,Auto">
<TabStrip SelectedIndex="{Binding SelectedTab, Mode=TwoWay}">
<TabStripItem Content="Logical Tree"/>
<TabStripItem Content="Visual Tree"/>
</TabStrip>
<ContentControl Content="{Binding Content}" Grid.Row="1"/>
<StackPanel Gap="4" Orientation="Horizontal" Grid.Row="2">
<TextBlock>Focused:</TextBlock>
<TextBlock Text="{Binding FocusedControl}"/>
<TextBlock>Pointer Over:</TextBlock>
<TextBlock Text="{Binding PointerOverElement}"/>
</StackPanel>
</Grid>
</UserControl>

52
src/Perspex.Diagnostics/DevTools.paml.cs

@ -0,0 +1,52 @@
using System;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Diagnostics.ViewModels;
using Perspex.Input;
using Perspex.Interactivity;
using Perspex.Markup.Xaml;
using ReactiveUI;
namespace Perspex.Diagnostics
{
public class DevTools : UserControl
{
public DevTools(IControl root)
{
this.InitializeComponent();
this.DataContext = new DevToolsViewModel(root);
}
public static IDisposable Attach(Window window)
{
return window.AddHandler(
KeyDownEvent,
WindowPreviewKeyDown,
RoutingStrategies.Tunnel);
}
private static void WindowPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F12)
{
Window window = new Window
{
Width = 1024,
Height = 512,
Content = new DevTools((IControl)sender),
DataTemplates = new DataTemplates
{
new ViewLocator<ReactiveObject>(),
}
};
window.Show();
}
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

27
src/Perspex.Diagnostics/Perspex.Diagnostics.csproj

@ -40,6 +40,14 @@
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<ProjectReference Include="..\Markup\Perspex.Markup.Xaml\Perspex.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Perspex.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\Markup\Perspex.Markup\Perspex.Markup.csproj">
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Perspex.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Animation\Perspex.Animation.csproj">
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project>
<Name>Perspex.Animation</Name>
@ -86,23 +94,24 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="LogManager.cs" />
<Compile Include="DevTools.cs" />
<Compile Include="Debug.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewLocator.cs" />
<Compile Include="ViewModels\DevToolsViewModel.cs" />
<Compile Include="ViewModels\VisualTreeViewModel.cs" />
<Compile Include="ViewModels\LogicalTreeViewModel.cs" />
<Compile Include="ViewModels\TreePageViewModel.cs" />
<Compile Include="ViewModels\PropertyDetails.cs" />
<Compile Include="ViewModels\ControlDetailsViewModel.cs" />
<Compile Include="ViewModels\LogicalTreeNode.cs" />
<Compile Include="ViewModels\TreeNode.cs" />
<Compile Include="ViewModels\VisualTreeNode.cs" />
<Compile Include="Views\TreePage.paml.cs">
<DependentUpon>TreePageView.paml</DependentUpon>
</Compile>
<Compile Include="DevTools.paml.cs">
<DependentUpon>DevTools.paml</DependentUpon>
</Compile>
<Compile Include="Views\ControlDetailsView.cs" />
<Compile Include="Views\GridRepeater.cs" />
<Compile Include="Views\VisualTreeView.cs" />
<Compile Include="Views\LogicalTreeView.cs" />
<Compile Include="Views\TreePage.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Splat">
@ -124,6 +133,12 @@
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<EmbeddedResource Include="DevTools.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Views\TreePageView.paml">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

2
src/Perspex.Diagnostics/ViewLocator.cs

@ -7,7 +7,7 @@ using Perspex.Controls.Templates;
namespace Perspex.Diagnostics
{
internal class ViewLocator<TViewModel> : IDataTemplate
public class ViewLocator<TViewModel> : IDataTemplate
{
public IControl Build(object data)
{

57
src/Perspex.Diagnostics/ViewModels/DevToolsViewModel.cs

@ -11,54 +11,63 @@ namespace Perspex.Diagnostics.ViewModels
{
internal class DevToolsViewModel : ReactiveObject
{
private Control _root;
private IControl _root;
private LogicalTreeViewModel _logicalTree;
private ReactiveObject _content;
private VisualTreeViewModel _visualTree;
private int _selectedTab;
private TreePageViewModel _logicalTree;
private TreePageViewModel _visualTree;
private readonly ObservableAsPropertyHelper<IInputElement> _focusedControl;
private readonly ObservableAsPropertyHelper<IInputElement> _pointerOverElement;
public DevToolsViewModel()
public DevToolsViewModel(IControl root)
{
this.WhenAnyValue(x => x.Root).Subscribe(x =>
_root = root;
_logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root));
_visualTree = new TreePageViewModel(VisualTreeNode.Create(root));
this.WhenAnyValue(x => x.SelectedTab).Subscribe(index =>
{
LogicalTree = new LogicalTreeViewModel(_root);
VisualTree = new VisualTreeViewModel(_root);
switch (index)
{
case 0:
Content = _logicalTree;
break;
case 1:
Content = _visualTree;
break;
}
});
_focusedControl = KeyboardDevice.Instance
.WhenAnyValue(x => x.FocusedElement)
.ToProperty(this, x => x.FocusedControl);
_pointerOverElement = this.WhenAnyValue(x => x.Root, x => x as TopLevel)
.Select(x => x?.GetObservable(TopLevel.PointerOverElementProperty) ?? Observable.Empty<IInputElement>())
.Switch()
.ToProperty(this, x => x.PointerOverElement);
}
public Control Root
{
get { return _root; }
set { this.RaiseAndSetIfChanged(ref _root, value); }
//_pointerOverElement = this.WhenAnyValue(x => x.Root, x => x as TopLevel)
// .Select(x => x?.GetObservable(TopLevel.PointerOverElementProperty) ?? Observable.Empty<IInputElement>())
// .Switch()
// .ToProperty(this, x => x.PointerOverElement);
}
public LogicalTreeViewModel LogicalTree
public ReactiveObject Content
{
get { return _logicalTree; }
private set { this.RaiseAndSetIfChanged(ref _logicalTree, value); }
get { return _content; }
private set { this.RaiseAndSetIfChanged(ref _content, value); }
}
public VisualTreeViewModel VisualTree
public int SelectedTab
{
get { return _visualTree; }
private set { this.RaiseAndSetIfChanged(ref _visualTree, value); }
get { return _selectedTab; }
set { this.RaiseAndSetIfChanged(ref _selectedTab, value); }
}
public IInputElement FocusedControl => _focusedControl.Value;
public IInputElement PointerOverElement => _pointerOverElement.Value;
//public IInputElement PointerOverElement => _pointerOverElement.Value;
}
}

34
src/Perspex.Diagnostics/ViewModels/LogicalTreeViewModel.cs

@ -1,34 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reactive.Linq;
using Perspex.Controls;
using ReactiveUI;
namespace Perspex.Diagnostics.ViewModels
{
internal class LogicalTreeViewModel : ReactiveObject
{
private LogicalTreeNode _selected;
private readonly ObservableAsPropertyHelper<ControlDetailsViewModel> _details;
public LogicalTreeViewModel(Control root)
{
Nodes = LogicalTreeNode.Create(root);
_details = this.WhenAnyValue(x => x.SelectedNode)
.Select(x => x != null ? new ControlDetailsViewModel(x.Control) : null)
.ToProperty(this, x => x.Details);
}
public LogicalTreeNode[] Nodes { get; }
public LogicalTreeNode SelectedNode
{
get { return _selected; }
set { this.RaiseAndSetIfChanged(ref _selected, value); }
}
public ControlDetailsViewModel Details => _details.Value;
}
}

7
src/Perspex.Diagnostics/ViewModels/TreeNode.cs

@ -13,6 +13,7 @@ namespace Perspex.Diagnostics.ViewModels
internal class TreeNode : ReactiveObject
{
private string _classes;
private bool _isExpanded = true;
public TreeNode(Control control)
{
@ -52,6 +53,12 @@ namespace Perspex.Diagnostics.ViewModels
private set { this.RaiseAndSetIfChanged(ref _classes, value); }
}
public bool IsExpanded
{
get { return _isExpanded; }
private set { this.RaiseAndSetIfChanged(ref _isExpanded, value); }
}
public string Type
{
get;

13
src/Perspex.Diagnostics/ViewModels/VisualTreeViewModel.cs → src/Perspex.Diagnostics/ViewModels/TreePageViewModel.cs

@ -2,28 +2,27 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Reactive.Linq;
using Perspex.Controls;
using ReactiveUI;
namespace Perspex.Diagnostics.ViewModels
{
internal class VisualTreeViewModel : ReactiveObject
internal class TreePageViewModel : ReactiveObject
{
private VisualTreeNode _selected;
private TreeNode _selected;
private readonly ObservableAsPropertyHelper<ControlDetailsViewModel> _details;
public VisualTreeViewModel(Control root)
public TreePageViewModel(TreeNode[] nodes)
{
Nodes = VisualTreeNode.Create(root);
Nodes = nodes;
_details = this.WhenAnyValue(x => x.SelectedNode)
.Select(x => x != null ? new ControlDetailsViewModel(x.Control) : null)
.ToProperty(this, x => x.Details);
}
public VisualTreeNode[] Nodes { get; }
public TreeNode[] Nodes { get; protected set; }
public VisualTreeNode SelectedNode
public TreeNode SelectedNode
{
get { return _selected; }
set { this.RaiseAndSetIfChanged(ref _selected, value); }

99
src/Perspex.Diagnostics/Views/LogicalTreeView.cs

@ -1,99 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Linq;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Diagnostics.ViewModels;
using ReactiveUI;
namespace Perspex.Diagnostics.Views
{
using Controls = Controls.Controls;
internal class LogicalTreeView : TreePage
{
private static readonly PerspexProperty<LogicalTreeViewModel> ViewModelProperty =
PerspexProperty.Register<LogicalTreeView, LogicalTreeViewModel>("ViewModel");
public LogicalTreeView()
{
InitializeComponent();
this.GetObservable(DataContextProperty)
.Subscribe(x => ViewModel = (LogicalTreeViewModel)x);
}
public LogicalTreeViewModel ViewModel
{
get { return GetValue(ViewModelProperty); }
private set { SetValue(ViewModelProperty, value); }
}
private void InitializeComponent()
{
TreeView tree;
Content = new Grid
{
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(1, GridUnitType.Star),
new ColumnDefinition(4, GridUnitType.Pixel),
new ColumnDefinition(3, GridUnitType.Star),
},
Children = new Controls
{
(tree = new TreeView
{
DataTemplates = new DataTemplates
{
new FuncTreeDataTemplate<LogicalTreeNode>(GetHeader, x => x.Children),
},
[!ItemsControl.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Nodes),
}),
new GridSplitter
{
Width = 4,
Orientation = Orientation.Vertical,
[Grid.ColumnProperty] = 1,
},
new ContentControl
{
[!ContentProperty] = this.WhenAnyValue(x => x.ViewModel.Details),
[Grid.ColumnProperty] = 2,
}
}
};
tree.GetObservable(TreeView.SelectedItemProperty)
.OfType<LogicalTreeNode>()
.Subscribe(x => ViewModel.SelectedNode = x);
}
private Control GetHeader(LogicalTreeNode node)
{
var result = new StackPanel
{
Orientation = Orientation.Horizontal,
Gap = 8,
Children = new Controls
{
new TextBlock
{
Text = node.Type,
},
new TextBlock
{
[!TextBlock.TextProperty] = node.WhenAnyValue(x => x.Classes),
}
}
};
result.PointerEnter += AddAdorner;
result.PointerLeave += RemoveAdorner;
return result;
}
}
}

18
src/Perspex.Diagnostics/Views/TreePage.cs → src/Perspex.Diagnostics/Views/TreePage.paml.cs

@ -1,19 +1,22 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Perspex.Controls;
using Perspex.Controls;
using Perspex.Controls.Primitives;
using Perspex.Controls.Shapes;
using Perspex.Diagnostics.ViewModels;
using Perspex.Input;
using Perspex.Markup.Xaml;
using Perspex.Media;
namespace Perspex.Diagnostics.Views
{
internal class TreePage : UserControl
public class TreePageView : UserControl
{
private Control _adorner;
public TreePageView()
{
this.InitializeComponent();
}
protected void AddAdorner(object sender, PointerEventArgs e)
{
var node = (TreeNode)((Control)sender).DataContext;
@ -39,5 +42,10 @@ namespace Perspex.Diagnostics.Views
_adorner = null;
}
}
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
}
}
}

24
src/Perspex.Diagnostics/Views/TreePageView.paml

@ -0,0 +1,24 @@
<UserControl xmlns="https://github.com/perspex"
xmlns:vm="clr-namespace:Perspex.Diagnostics.ViewModels;assembly=Perspex.Diagnostics">
<Grid ColumnDefinitions="*,4,3*">
<TreeView Name="tree" Items="{Binding Nodes}" SelectedItem="{Binding SelectedNode, Mode=TwoWay}">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="vm:TreeNode"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" Gap="8">
<TextBlock Text="{Binding Type}"/>
<TextBlock Text="{Binding Classes}"/>
</StackPanel>
</TreeDataTemplate>
</TreeView.DataTemplates>
<!--<TreeView.Styles>
<Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
</Style>
</TreeView.Styles>-->
</TreeView>
<GridSplitter Width="4" Orientation="Vertical" Grid.Column="1"/>
<ContentControl Content="{Binding Details}" Grid.Column="2"/>
</Grid>
</UserControl>

101
src/Perspex.Diagnostics/Views/VisualTreeView.cs

@ -1,101 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Linq;
using Perspex.Controls;
using Perspex.Controls.Templates;
using Perspex.Diagnostics.ViewModels;
using Perspex.Media;
using ReactiveUI;
namespace Perspex.Diagnostics.Views
{
using Controls = Controls.Controls;
internal class VisualTreeView : TreePage
{
private static readonly PerspexProperty<VisualTreeViewModel> ViewModelProperty =
PerspexProperty.Register<VisualTreeView, VisualTreeViewModel>("ViewModel");
public VisualTreeView()
{
InitializeComponent();
this.GetObservable(DataContextProperty)
.Subscribe(x => ViewModel = (VisualTreeViewModel)x);
}
public VisualTreeViewModel ViewModel
{
get { return GetValue(ViewModelProperty); }
private set { SetValue(ViewModelProperty, value); }
}
private void InitializeComponent()
{
TreeView tree;
Content = new Grid
{
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(1, GridUnitType.Star),
new ColumnDefinition(4, GridUnitType.Pixel),
new ColumnDefinition(3, GridUnitType.Star),
},
Children = new Controls
{
(tree = new TreeView
{
DataTemplates = new DataTemplates
{
new FuncTreeDataTemplate<VisualTreeNode>(GetHeader, x => x.Children),
},
[!ItemsControl.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Nodes),
}),
new GridSplitter
{
Width = 4,
Orientation = Orientation.Vertical,
[Grid.ColumnProperty] = 1,
},
new ContentControl
{
[!ContentProperty] = this.WhenAnyValue(x => x.ViewModel.Details),
[Grid.ColumnProperty] = 2,
}
}
};
tree.GetObservable(TreeView.SelectedItemProperty)
.OfType<VisualTreeNode>()
.Subscribe(x => ViewModel.SelectedNode = x);
}
private Control GetHeader(VisualTreeNode node)
{
var result = new StackPanel
{
Orientation = Orientation.Horizontal,
Gap = 8,
Children = new Controls
{
new TextBlock
{
FontStyle = node.IsInTemplate ? FontStyle.Italic : FontStyle.Normal,
Text = node.Type,
},
new TextBlock
{
[!TextBlock.TextProperty] = node.WhenAnyValue(x => x.Classes),
}
}
};
result.PointerEnter += AddAdorner;
result.PointerLeave += RemoveAdorner;
return result;
}
}
}
Loading…
Cancel
Save