mirror of https://github.com/icsharpcode/ILSpy.git
Browse Source
git-subtree-dir: SharpTreeView git-subtree-split: 886d615dc7ae9ffbe2a4f466455fd32e81547119pull/1/head
commit
a5ac9d09ed
17 changed files with 2409 additions and 0 deletions
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows; |
||||
using System.Windows.Markup; |
||||
using System.Windows.Data; |
||||
using System.Globalization; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class CollapsedWhenFalse : MarkupExtension, IValueConverter |
||||
{ |
||||
public static CollapsedWhenFalse Instance = new CollapsedWhenFalse(); |
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider) |
||||
{ |
||||
return Instance; |
||||
} |
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
||||
{ |
||||
return (bool)value ? Visibility.Visible : Visibility.Collapsed; |
||||
} |
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
||||
{ |
||||
throw new NotImplementedException(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public enum DropEffect |
||||
{ |
||||
None, Move, Copy, Link |
||||
} |
||||
} |
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Input; |
||||
using System.Windows.Data; |
||||
using System.Windows; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
class EditTextBox : TextBox |
||||
{ |
||||
static EditTextBox() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(EditTextBox), |
||||
new FrameworkPropertyMetadata(typeof(EditTextBox))); |
||||
} |
||||
|
||||
public EditTextBox() |
||||
{ |
||||
Loaded += delegate { Init(); }; |
||||
} |
||||
|
||||
public SharpTreeViewItem Item { get; set; } |
||||
|
||||
public SharpTreeNode Node |
||||
{ |
||||
get { return Item.Node; } |
||||
} |
||||
|
||||
void Init() |
||||
{ |
||||
Text = Node.LoadEditText(); |
||||
Focus(); |
||||
SelectAll(); |
||||
} |
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e) |
||||
{ |
||||
if (e.Key == Key.Enter) { |
||||
Commit(); |
||||
} |
||||
else if (e.Key == Key.Escape) { |
||||
Node.IsEditing = false; |
||||
} |
||||
} |
||||
|
||||
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) |
||||
{ |
||||
if (Node.IsEditing) { |
||||
Commit(); |
||||
} |
||||
} |
||||
|
||||
bool commiting; |
||||
|
||||
void Commit() |
||||
{ |
||||
if (!commiting) { |
||||
commiting = true; |
||||
|
||||
Node.IsEditing = false; |
||||
if (!Node.SaveEditText(Text)) { |
||||
Item.Focus(); |
||||
} |
||||
Node.RaisePropertyChanged("Text"); |
||||
|
||||
//if (Node.SaveEditText(Text)) {
|
||||
// Node.IsEditing = false;
|
||||
// Node.RaisePropertyChanged("Text");
|
||||
//}
|
||||
//else {
|
||||
// Init();
|
||||
//}
|
||||
|
||||
commiting = false; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Media; |
||||
using System.Windows; |
||||
using System.Collections; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public static class ExtensionMethods |
||||
{ |
||||
public static T FindAncestor<T>(this DependencyObject d) where T : class |
||||
{ |
||||
return AncestorsAndSelf(d).OfType<T>().FirstOrDefault(); |
||||
} |
||||
|
||||
public static IEnumerable<DependencyObject> AncestorsAndSelf(this DependencyObject d) |
||||
{ |
||||
while (d != null) { |
||||
yield return d; |
||||
d = VisualTreeHelper.GetParent(d); |
||||
} |
||||
} |
||||
|
||||
public static void AddOnce(this IList list, object item) |
||||
{ |
||||
if (!list.Contains(item)) { |
||||
list.Add(item); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Documents; |
||||
using System.Windows; |
||||
using System.Windows.Media; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class GeneralAdorner : Adorner |
||||
{ |
||||
public GeneralAdorner(UIElement target) |
||||
: base(target) |
||||
{ |
||||
} |
||||
|
||||
FrameworkElement child; |
||||
|
||||
public FrameworkElement Child |
||||
{ |
||||
get |
||||
{ |
||||
return child; |
||||
} |
||||
set |
||||
{ |
||||
if (child != value) { |
||||
RemoveVisualChild(child); |
||||
RemoveLogicalChild(child); |
||||
child = value; |
||||
AddLogicalChild(value); |
||||
AddVisualChild(value); |
||||
InvalidateMeasure(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected override int VisualChildrenCount |
||||
{ |
||||
get { return child == null ? 0 : 1; } |
||||
} |
||||
|
||||
protected override Visual GetVisualChild(int index) |
||||
{ |
||||
return child; |
||||
} |
||||
|
||||
protected override Size MeasureOverride(Size constraint) |
||||
{ |
||||
if (child != null) { |
||||
child.Measure(constraint); |
||||
return child.DesiredSize; |
||||
} |
||||
return new Size(); |
||||
} |
||||
|
||||
protected override Size ArrangeOverride(Size finalSize) |
||||
{ |
||||
if (child != null) { |
||||
child.Arrange(new Rect(finalSize)); |
||||
return finalSize; |
||||
} |
||||
return new Size(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<PropertyGroup> |
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
||||
<ProductVersion>9.0.30729</ProductVersion> |
||||
<SchemaVersion>2.0</SchemaVersion> |
||||
<ProjectGuid>{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}</ProjectGuid> |
||||
<OutputType>library</OutputType> |
||||
<AppDesignerFolder>Properties</AppDesignerFolder> |
||||
<RootNamespace>ICSharpCode.TreeView</RootNamespace> |
||||
<AssemblyName>ICSharpCode.TreeView</AssemblyName> |
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
||||
<FileAlignment>512</FileAlignment> |
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
||||
<WarningLevel>4</WarningLevel> |
||||
<OutputPath>..\..\..\..\bin\</OutputPath> |
||||
<TargetFrameworkProfile> |
||||
</TargetFrameworkProfile> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<DebugType>full</DebugType> |
||||
<Optimize>false</Optimize> |
||||
<OutputPath>..\..\..\..\bin\</OutputPath> |
||||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
</PropertyGroup> |
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
||||
<DebugType>pdbonly</DebugType> |
||||
<Optimize>true</Optimize> |
||||
<OutputPath>..\..\..\..\bin\</OutputPath> |
||||
<DefineConstants>TRACE</DefineConstants> |
||||
<ErrorReport>prompt</ErrorReport> |
||||
<WarningLevel>4</WarningLevel> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Reference Include="System" /> |
||||
<Reference Include="System.Core"> |
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="System.Xml.Linq"> |
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="System.Data.DataSetExtensions"> |
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework> |
||||
</Reference> |
||||
<Reference Include="System.Data" /> |
||||
<Reference Include="System.Xml" /> |
||||
<Reference Include="System.Xaml" /> |
||||
<Reference Include="WindowsBase" /> |
||||
<Reference Include="PresentationCore" /> |
||||
<Reference Include="PresentationFramework" /> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Page Include="Themes\Generic.xaml"> |
||||
<Generator>MSBuild:Compile</Generator> |
||||
<SubType>Designer</SubType> |
||||
</Page> |
||||
</ItemGroup> |
||||
<ItemGroup> |
||||
<Compile Include="..\..\..\Main\GlobalAssemblyInfo.cs"> |
||||
<Link>Properties\GlobalAssemblyInfo.cs</Link> |
||||
</Compile> |
||||
<Compile Include="Converters.cs" /> |
||||
<Compile Include="DropEffect.cs" /> |
||||
<Compile Include="EditTextBox.cs" /> |
||||
<Compile Include="ExtensionMethods.cs" /> |
||||
<Compile Include="GeneralAdorner.cs" /> |
||||
<Compile Include="InsertMarker.cs" /> |
||||
<Compile Include="LinesRenderer.cs" /> |
||||
<Compile Include="Properties\AssemblyInfo.cs"> |
||||
<SubType>Code</SubType> |
||||
</Compile> |
||||
<Compile Include="SharpGridView.cs" /> |
||||
<Compile Include="SharpTreeNode.cs" /> |
||||
<Compile Include="SharpTreeNodeCollection.cs" /> |
||||
<Compile Include="SharpTreeNodeView.cs" /> |
||||
<Compile Include="SharpTreeView.cs" /> |
||||
<Compile Include="SharpTreeViewItem.cs" /> |
||||
<Compile Include="TreeFlattener.cs" /> |
||||
<AppDesigner Include="Properties\" /> |
||||
</ItemGroup> |
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
||||
Other similar extension points exist, see Microsoft.Common.targets. |
||||
<Target Name="BeforeBuild"> |
||||
</Target> |
||||
<Target Name="AfterBuild"> |
||||
</Target> |
||||
--> |
||||
</Project> |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Controls; |
||||
using System.Windows; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class InsertMarker : Control |
||||
{ |
||||
static InsertMarker() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(InsertMarker), |
||||
new FrameworkPropertyMetadata(typeof(InsertMarker))); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,57 @@
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows; |
||||
using System.Windows.Media; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
class LinesRenderer : FrameworkElement |
||||
{ |
||||
static LinesRenderer() |
||||
{ |
||||
pen = new Pen(Brushes.LightGray, 1); |
||||
pen.Freeze(); |
||||
} |
||||
|
||||
static Pen pen; |
||||
|
||||
SharpTreeNodeView NodeView |
||||
{ |
||||
get { return TemplatedParent as SharpTreeNodeView; } |
||||
} |
||||
|
||||
protected override void OnRender(DrawingContext dc) |
||||
{ |
||||
var indent = NodeView.CalculateIndent(); |
||||
var p = new Point(indent + 4.5, 0); |
||||
|
||||
if (!NodeView.Node.IsRoot || NodeView.ParentTreeView.ShowRootExpander) { |
||||
dc.DrawLine(pen, new Point(p.X, ActualHeight / 2), new Point(p.X + 10, ActualHeight / 2)); |
||||
} |
||||
|
||||
if (NodeView.Node.IsRoot) return; |
||||
|
||||
if (NodeView.Node.IsLast) { |
||||
dc.DrawLine(pen, p, new Point(p.X, ActualHeight / 2)); |
||||
} |
||||
else { |
||||
dc.DrawLine(pen, p, new Point(p.X, ActualHeight)); |
||||
} |
||||
|
||||
var current = NodeView.Node; |
||||
while (true) { |
||||
p.X -= 19; |
||||
current = current.Parent; |
||||
if (p.X < 0) break; |
||||
if (!current.IsLast) { |
||||
dc.DrawLine(pen, p, new Point(p.X, ActualHeight)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,42 @@
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System.Reflection; |
||||
using System.Resources; |
||||
using System.Runtime.CompilerServices; |
||||
using System.Runtime.InteropServices; |
||||
using System.Windows; |
||||
using System.Windows.Markup; |
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("ICSharpCode.TreeView")] |
||||
[assembly: AssemblyDescription("")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo( |
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)] |
||||
|
||||
|
||||
[assembly: XmlnsPrefix("http://icsharpcode.net/sharpdevelop/treeview", "treeview")] |
||||
|
||||
[assembly: XmlnsDefinition("http://icsharpcode.net/sharpdevelop/treeview", "ICSharpCode.TreeView")] |
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Controls; |
||||
using System.Windows; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class SharpGridView : GridView |
||||
{ |
||||
static SharpGridView() |
||||
{ |
||||
ItemContainerStyleKey = |
||||
new ComponentResourceKey(typeof(SharpTreeView), "GridViewItemContainerStyleKey"); |
||||
} |
||||
|
||||
public static ResourceKey ItemContainerStyleKey { get; private set; } |
||||
|
||||
protected override object ItemContainerDefaultStyleKey |
||||
{ |
||||
get |
||||
{ |
||||
return ItemContainerStyleKey; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,612 @@
@@ -0,0 +1,612 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows; |
||||
using System.ComponentModel; |
||||
using System.Collections.ObjectModel; |
||||
using System.Windows.Controls; |
||||
using System.Collections.Specialized; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class SharpTreeNode : INotifyPropertyChanged |
||||
{ |
||||
#region Main
|
||||
|
||||
static SharpTreeNode() |
||||
{ |
||||
SelectedNodes = new List<SharpTreeNode>(); |
||||
ActiveNodes = new List<SharpTreeNode>(); |
||||
StartCuttedDataWatcher(); |
||||
} |
||||
|
||||
public static List<SharpTreeNode> SelectedNodes { get; private set; } |
||||
public static List<SharpTreeNode> ActiveNodes { get; private set; } |
||||
|
||||
static SharpTreeNode[] ActiveNodesArray |
||||
{ |
||||
get |
||||
{ |
||||
return ActiveNodes.ToArray(); |
||||
} |
||||
} |
||||
|
||||
public SharpTreeNode() |
||||
{ |
||||
Children = new SharpTreeNodeCollection(this); |
||||
} |
||||
|
||||
public SharpTreeNodeCollection Children { get; private set; } |
||||
public SharpTreeNode Parent { get; internal set; } |
||||
|
||||
public virtual object Text |
||||
{ |
||||
get { return null; } |
||||
} |
||||
|
||||
public virtual object Icon |
||||
{ |
||||
get { return null; } |
||||
} |
||||
|
||||
public virtual object ToolTip |
||||
{ |
||||
get { return null; } |
||||
} |
||||
|
||||
public int Level |
||||
{ |
||||
get { return Parent != null ? Parent.Level + 1 : 0; } |
||||
} |
||||
|
||||
public bool IsRoot |
||||
{ |
||||
get { return Parent == null; } |
||||
} |
||||
|
||||
//bool isSelected;
|
||||
|
||||
//public bool IsSelected
|
||||
//{
|
||||
// get { return isSelected; }
|
||||
// set
|
||||
// {
|
||||
// isSelected = value;
|
||||
// RaisePropertyChanged("IsSelected");
|
||||
// }
|
||||
//}
|
||||
|
||||
public virtual ContextMenu GetContextMenu() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
internal protected void OnChildrenChanged(NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
RaisePropertyChanged("ShowExpander"); |
||||
RaiseIsLastChangedIfNeeded(e); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Expanding / LazyLoading
|
||||
|
||||
public event EventHandler Collapsing; |
||||
|
||||
public virtual object ExpandedIcon |
||||
{ |
||||
get { return Icon; } |
||||
} |
||||
|
||||
public virtual bool ShowExpander |
||||
{ |
||||
get { return Children.Count > 0 || LazyLoading; } |
||||
} |
||||
|
||||
//public virtual bool ShowLoading
|
||||
//{
|
||||
// get { return false; }
|
||||
//}
|
||||
|
||||
bool isExpanded; |
||||
|
||||
public bool IsExpanded |
||||
{ |
||||
get { return isExpanded; } |
||||
set |
||||
{ |
||||
if (isExpanded != value) { |
||||
isExpanded = value; |
||||
if (isExpanded) { |
||||
EnsureLazyChildren(); |
||||
} |
||||
else { |
||||
if (Collapsing != null) { |
||||
Collapsing(this, EventArgs.Empty); |
||||
} |
||||
} |
||||
RaisePropertyChanged("IsExpanded"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool lazyLoading; |
||||
|
||||
public bool LazyLoading |
||||
{ |
||||
get { return lazyLoading; } |
||||
set |
||||
{ |
||||
lazyLoading = value; |
||||
if (lazyLoading) { |
||||
IsExpanded = false; |
||||
} |
||||
RaisePropertyChanged("LazyLoading"); |
||||
RaisePropertyChanged("ShowExpander"); |
||||
} |
||||
} |
||||
|
||||
bool showIcon; |
||||
|
||||
public bool ShowIcon |
||||
{ |
||||
get { return showIcon; } |
||||
set { |
||||
showIcon = value; |
||||
RaisePropertyChanged("ShowIcon"); |
||||
} |
||||
} |
||||
|
||||
public virtual void LoadChildren() |
||||
{ |
||||
} |
||||
|
||||
public void EnsureLazyChildren() |
||||
{ |
||||
if (LazyLoading) { |
||||
LoadChildren(); |
||||
LazyLoading = false; |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Ancestors / Descendants
|
||||
|
||||
public IEnumerable<SharpTreeNode> Descendants() |
||||
{ |
||||
foreach (var child in Children) { |
||||
foreach (var child2 in child.DescendantsAndSelf()) { |
||||
yield return child2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<SharpTreeNode> DescendantsAndSelf() |
||||
{ |
||||
yield return this; |
||||
foreach (var child in Descendants()) { |
||||
yield return child; |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<SharpTreeNode> ExpandedDescendants() |
||||
{ |
||||
foreach (var child in Children) { |
||||
foreach (var child2 in child.ExpandedDescendantsAndSelf()) { |
||||
yield return child2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<SharpTreeNode> ExpandedDescendantsAndSelf() |
||||
{ |
||||
yield return this; |
||||
if (IsExpanded) { |
||||
foreach (var child in Children) { |
||||
foreach (var child2 in child.ExpandedDescendantsAndSelf()) { |
||||
yield return child2; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<SharpTreeNode> Ancestors() |
||||
{ |
||||
var node = this; |
||||
while (node.Parent != null) { |
||||
yield return node.Parent; |
||||
node = node.Parent; |
||||
} |
||||
} |
||||
|
||||
public IEnumerable<SharpTreeNode> AncestorsAndSelf() |
||||
{ |
||||
yield return this; |
||||
foreach (var node in Ancestors()) { |
||||
yield return node; |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Editing
|
||||
|
||||
public virtual bool IsEditable |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
bool isEditing; |
||||
|
||||
public bool IsEditing |
||||
{ |
||||
get { return isEditing; } |
||||
set |
||||
{ |
||||
if (isEditing != value) { |
||||
isEditing = value; |
||||
RaisePropertyChanged("IsEditing"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public virtual string LoadEditText() |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
public virtual bool SaveEditText(string value) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Checkboxes
|
||||
|
||||
public virtual bool IsCheckable |
||||
{ |
||||
get { return false; } |
||||
} |
||||
|
||||
bool? isChecked; |
||||
|
||||
public bool? IsChecked |
||||
{ |
||||
get { return isChecked; } |
||||
set |
||||
{ |
||||
SetIsChecked(value, true); |
||||
} |
||||
} |
||||
|
||||
void SetIsChecked(bool? value, bool update) |
||||
{ |
||||
if (isChecked != value) { |
||||
isChecked = value; |
||||
|
||||
if (update) { |
||||
if (IsChecked != null) { |
||||
foreach (var child in Descendants()) { |
||||
if (child.IsCheckable) { |
||||
child.SetIsChecked(IsChecked, false); |
||||
} |
||||
} |
||||
} |
||||
|
||||
foreach (var parent in Ancestors()) { |
||||
if (parent.IsCheckable) { |
||||
if (!parent.TryValueForIsChecked(true)) { |
||||
if (!parent.TryValueForIsChecked(false)) { |
||||
parent.SetIsChecked(null, false); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
RaisePropertyChanged("IsChecked"); |
||||
} |
||||
} |
||||
|
||||
bool TryValueForIsChecked(bool? value) |
||||
{ |
||||
if (Children.Where(n => n.IsCheckable).All(n => n.IsChecked == value)) { |
||||
SetIsChecked(value, false); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Cut / Copy / Paste / Delete
|
||||
|
||||
static List<SharpTreeNode> cuttedNodes = new List<SharpTreeNode>(); |
||||
static IDataObject cuttedData; |
||||
static EventHandler requerySuggestedHandler; // for weak event
|
||||
|
||||
static void StartCuttedDataWatcher() |
||||
{ |
||||
requerySuggestedHandler = new EventHandler(CommandManager_RequerySuggested); |
||||
CommandManager.RequerySuggested += requerySuggestedHandler; |
||||
} |
||||
|
||||
static void CommandManager_RequerySuggested(object sender, EventArgs e) |
||||
{ |
||||
if (cuttedData != null && !Clipboard.IsCurrent(cuttedData)) { |
||||
ClearCuttedData(); |
||||
} |
||||
} |
||||
|
||||
static void ClearCuttedData() |
||||
{ |
||||
foreach (var node in cuttedNodes) { |
||||
node.IsCut = false; |
||||
} |
||||
cuttedNodes.Clear(); |
||||
cuttedData = null; |
||||
} |
||||
|
||||
//static public IEnumerable<SharpTreeNode> PurifyNodes(IEnumerable<SharpTreeNode> nodes)
|
||||
//{
|
||||
// var list = nodes.ToList();
|
||||
// var array = list.ToArray();
|
||||
// foreach (var node1 in array) {
|
||||
// foreach (var node2 in array) {
|
||||
// if (node1.Descendants().Contains(node2)) {
|
||||
// list.Remove(node2);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return list;
|
||||
//}
|
||||
|
||||
bool isCut; |
||||
|
||||
public bool IsCut |
||||
{ |
||||
get { return isCut; } |
||||
private set |
||||
{ |
||||
isCut = value; |
||||
RaisePropertyChanged("IsCut"); |
||||
} |
||||
} |
||||
|
||||
internal bool InternalCanCut() |
||||
{ |
||||
return InternalCanCopy() && InternalCanDelete(); |
||||
} |
||||
|
||||
internal void InternalCut() |
||||
{ |
||||
ClearCuttedData(); |
||||
cuttedData = Copy(ActiveNodesArray); |
||||
Clipboard.SetDataObject(cuttedData); |
||||
|
||||
foreach (var node in ActiveNodes) { |
||||
node.IsCut = true; |
||||
cuttedNodes.Add(node); |
||||
} |
||||
} |
||||
|
||||
internal bool InternalCanCopy() |
||||
{ |
||||
return CanCopy(ActiveNodesArray); |
||||
} |
||||
|
||||
internal void InternalCopy() |
||||
{ |
||||
Clipboard.SetDataObject(Copy(ActiveNodesArray)); |
||||
} |
||||
|
||||
internal bool InternalCanPaste() |
||||
{ |
||||
return CanPaste(Clipboard.GetDataObject()); |
||||
} |
||||
|
||||
internal void InternalPaste() |
||||
{ |
||||
Paste(Clipboard.GetDataObject()); |
||||
|
||||
if (cuttedData != null) { |
||||
DeleteCore(cuttedNodes.ToArray()); |
||||
ClearCuttedData(); |
||||
} |
||||
} |
||||
|
||||
internal bool InternalCanDelete() |
||||
{ |
||||
return CanDelete(ActiveNodesArray); |
||||
} |
||||
|
||||
internal void InternalDelete() |
||||
{ |
||||
Delete(ActiveNodesArray); |
||||
} |
||||
|
||||
public virtual bool CanDelete(SharpTreeNode[] nodes) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
public virtual void Delete(SharpTreeNode[] nodes) |
||||
{ |
||||
} |
||||
|
||||
public virtual void DeleteCore(SharpTreeNode[] nodes) |
||||
{ |
||||
} |
||||
|
||||
public virtual bool CanCopy(SharpTreeNode[] nodes) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
public virtual IDataObject Copy(SharpTreeNode[] nodes) |
||||
{ |
||||
return null; |
||||
} |
||||
|
||||
public virtual bool CanPaste(IDataObject data) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
public virtual void Paste(IDataObject data) |
||||
{ |
||||
EnsureLazyChildren(); |
||||
Drop(data, Children.Count, DropEffect.Copy); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Drag and Drop
|
||||
|
||||
internal bool InternalCanDrag() |
||||
{ |
||||
return CanDrag(ActiveNodesArray); |
||||
} |
||||
|
||||
internal void InternalDrag(DependencyObject dragSource) |
||||
{ |
||||
DragDrop.DoDragDrop(dragSource, Copy(ActiveNodesArray), DragDropEffects.All); |
||||
} |
||||
|
||||
internal bool InternalCanDrop(DragEventArgs e, int index) |
||||
{ |
||||
var finalEffect = GetFinalEffect(e, index); |
||||
e.Effects = GetDragDropEffects(finalEffect); |
||||
return finalEffect != DropEffect.None; |
||||
} |
||||
|
||||
internal void InternalDrop(DragEventArgs e, int index) |
||||
{ |
||||
if (LazyLoading) { |
||||
EnsureLazyChildren(); |
||||
index = Children.Count; |
||||
} |
||||
|
||||
var finalEffect = GetFinalEffect(e, index); |
||||
Drop(e.Data, index, finalEffect); |
||||
|
||||
if (finalEffect == DropEffect.Move) { |
||||
DeleteCore(ActiveNodesArray); |
||||
} |
||||
} |
||||
|
||||
DropEffect GetFinalEffect(DragEventArgs e, int index) |
||||
{ |
||||
var requestedEffect = GetDropEffect(e); |
||||
var result = CanDrop(e.Data, requestedEffect); |
||||
if (result == DropEffect.Move) { |
||||
if (!CanDelete(ActiveNodesArray)) { |
||||
return DropEffect.None; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static DropEffect GetDropEffect(DragEventArgs e) |
||||
{ |
||||
if (e.Data != null) { |
||||
var all = DragDropKeyStates.ControlKey | DragDropKeyStates.ShiftKey | DragDropKeyStates.AltKey; |
||||
|
||||
if ((e.KeyStates & all) == DragDropKeyStates.ControlKey) { |
||||
return DropEffect.Copy; |
||||
} |
||||
if ((e.KeyStates & all) == DragDropKeyStates.AltKey) { |
||||
return DropEffect.Link; |
||||
} |
||||
if ((e.KeyStates & all) == (DragDropKeyStates.ControlKey | DragDropKeyStates.ShiftKey)) { |
||||
return DropEffect.Link; |
||||
} |
||||
return DropEffect.Move; |
||||
} |
||||
return DropEffect.None; |
||||
} |
||||
|
||||
static DragDropEffects GetDragDropEffects(DropEffect effect) |
||||
{ |
||||
switch (effect) { |
||||
case DropEffect.Copy: |
||||
return DragDropEffects.Copy; |
||||
case DropEffect.Link: |
||||
return DragDropEffects.Link; |
||||
case DropEffect.Move: |
||||
return DragDropEffects.Move; |
||||
} |
||||
return DragDropEffects.None; |
||||
} |
||||
|
||||
public virtual bool CanDrag(SharpTreeNode[] nodes) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
public virtual DropEffect CanDrop(IDataObject data, DropEffect requestedEffect) |
||||
{ |
||||
return DropEffect.None; |
||||
} |
||||
|
||||
public virtual void Drop(IDataObject data, int index, DropEffect finalEffect) |
||||
{ |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region IsLast (for TreeView lines)
|
||||
|
||||
public bool IsLast |
||||
{ |
||||
get |
||||
{ |
||||
return Parent == null || |
||||
Parent.Children[Parent.Children.Count - 1] == this; |
||||
} |
||||
} |
||||
|
||||
void RaiseIsLastChangedIfNeeded(NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
switch (e.Action) { |
||||
case NotifyCollectionChangedAction.Add: |
||||
if (e.NewStartingIndex == Children.Count - 1) { |
||||
if (Children.Count > 1) { |
||||
Children[Children.Count - 2].RaisePropertyChanged("IsLast"); |
||||
} |
||||
Children[Children.Count - 1].RaisePropertyChanged("IsLast"); |
||||
} |
||||
break; |
||||
case NotifyCollectionChangedAction.Remove: |
||||
if (e.OldStartingIndex == Children.Count) { |
||||
if (Children.Count > 0) { |
||||
Children[Children.Count - 1].RaisePropertyChanged("IsLast"); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region INotifyPropertyChanged Members
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged; |
||||
|
||||
public void RaisePropertyChanged(string name) |
||||
{ |
||||
if (PropertyChanged != null) { |
||||
PropertyChanged(this, new PropertyChangedEventArgs(name)); |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Collections.ObjectModel; |
||||
using System.Collections.Specialized; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class SharpTreeNodeCollection : ObservableCollection<SharpTreeNode> |
||||
{ |
||||
public SharpTreeNodeCollection(SharpTreeNode parent) |
||||
{ |
||||
Parent = parent; |
||||
} |
||||
|
||||
public SharpTreeNode Parent { get; private set; } |
||||
|
||||
protected override void InsertItem(int index, SharpTreeNode node) |
||||
{ |
||||
node.Parent = Parent; |
||||
base.InsertItem(index, node); |
||||
} |
||||
|
||||
protected override void RemoveItem(int index) |
||||
{ |
||||
var node = this[index]; |
||||
node.Parent = null; |
||||
base.RemoveItem(index); |
||||
} |
||||
|
||||
protected override void ClearItems() |
||||
{ |
||||
foreach (var node in this) { |
||||
node.Parent = null; |
||||
} |
||||
base.ClearItems(); |
||||
} |
||||
|
||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
base.OnCollectionChanged(e); |
||||
Parent.OnChildrenChanged(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,149 @@
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Controls; |
||||
using System.Windows; |
||||
using System.Windows.Controls.Primitives; |
||||
using System.Windows.Media; |
||||
using System.Windows.Input; |
||||
using System.ComponentModel; |
||||
using System.Collections.Specialized; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class SharpTreeNodeView : Control |
||||
{ |
||||
static SharpTreeNodeView() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(SharpTreeNodeView), |
||||
new FrameworkPropertyMetadata(typeof(SharpTreeNodeView))); |
||||
} |
||||
|
||||
public static readonly DependencyProperty TextBackgroundProperty = |
||||
DependencyProperty.Register("TextBackground", typeof(Brush), typeof(SharpTreeNodeView)); |
||||
|
||||
public Brush TextBackground |
||||
{ |
||||
get { return (Brush)GetValue(TextBackgroundProperty); } |
||||
set { SetValue(TextBackgroundProperty, value); } |
||||
} |
||||
|
||||
public SharpTreeNode Node |
||||
{ |
||||
get { return DataContext as SharpTreeNode; } |
||||
} |
||||
|
||||
public SharpTreeViewItem ParentItem { get; private set; } |
||||
|
||||
public SharpTreeView ParentTreeView |
||||
{ |
||||
get { return ParentItem.ParentTreeView; } |
||||
} |
||||
|
||||
internal LinesRenderer LinesRenderer { get; private set; } |
||||
|
||||
public override void OnApplyTemplate() |
||||
{ |
||||
base.OnApplyTemplate(); |
||||
LinesRenderer = Template.FindName("linesRenderer", this) as LinesRenderer; |
||||
UpdateTemplate(); |
||||
} |
||||
|
||||
protected override void OnVisualParentChanged(DependencyObject oldParent) |
||||
{ |
||||
base.OnVisualParentChanged(oldParent); |
||||
ParentItem = this.FindAncestor<SharpTreeViewItem>(); |
||||
ParentItem.NodeView = this; |
||||
} |
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) |
||||
{ |
||||
base.OnPropertyChanged(e); |
||||
if (e.Property == DataContextProperty) { |
||||
UpdateDataContext(e.OldValue as SharpTreeNode, e.NewValue as SharpTreeNode); |
||||
} |
||||
} |
||||
|
||||
void UpdateDataContext(SharpTreeNode oldNode, SharpTreeNode newNode) |
||||
{ |
||||
if (newNode != null) { |
||||
newNode.Collapsing += Node_Collapsing; |
||||
newNode.PropertyChanged += Node_PropertyChanged; |
||||
if (Template != null) { |
||||
UpdateTemplate(); |
||||
} |
||||
} |
||||
if (oldNode != null) { |
||||
oldNode.Collapsing -= Node_Collapsing; |
||||
oldNode.PropertyChanged -= Node_PropertyChanged; |
||||
} |
||||
} |
||||
|
||||
void Node_PropertyChanged(object sender, PropertyChangedEventArgs e) |
||||
{ |
||||
if (e.PropertyName == "IsEditing") { |
||||
OnIsEditingChanged(); |
||||
} |
||||
else if (e.PropertyName == "IsLast") { |
||||
if (ParentTreeView.ShowLines) { |
||||
foreach (var child in Node.ExpandedDescendantsAndSelf()) { |
||||
var container = ParentTreeView.ItemContainerGenerator.ContainerFromItem(child) as SharpTreeViewItem; |
||||
if (container != null) { |
||||
container.NodeView.LinesRenderer.InvalidateVisual(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Node_Collapsing(object sender, EventArgs e) |
||||
{ |
||||
ParentTreeView.HandleCollapsing(Node); |
||||
} |
||||
|
||||
void OnIsEditingChanged() |
||||
{ |
||||
var textEditorContainer = Template.FindName("textEditorContainer", this) as Border; |
||||
if (Node.IsEditing) { |
||||
textEditorContainer.Child = new EditTextBox() { Item = ParentItem }; |
||||
} |
||||
else { |
||||
textEditorContainer.Child = null; |
||||
} |
||||
} |
||||
|
||||
void UpdateTemplate() |
||||
{ |
||||
var spacer = Template.FindName("spacer", this) as FrameworkElement; |
||||
spacer.Width = CalculateIndent(); |
||||
|
||||
var expander = Template.FindName("expander", this) as ToggleButton; |
||||
if (ParentTreeView.Root == Node && !ParentTreeView.ShowRootExpander) { |
||||
expander.Visibility = Visibility.Collapsed; |
||||
} |
||||
else { |
||||
expander.ClearValue(VisibilityProperty); |
||||
} |
||||
} |
||||
|
||||
internal double CalculateIndent() |
||||
{ |
||||
var result = 19 * Node.Level; |
||||
if (ParentTreeView.ShowRoot) { |
||||
if (!ParentTreeView.ShowRootExpander) { |
||||
if (ParentTreeView.Root != Node) { |
||||
result -= 15; |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
result -= 19; |
||||
} |
||||
return result; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,458 @@
@@ -0,0 +1,458 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Controls; |
||||
using System.Windows; |
||||
using System.Windows.Media; |
||||
using System.Windows.Data; |
||||
using System.Windows.Documents; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class SharpTreeView : ListView |
||||
{ |
||||
static SharpTreeView() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(typeof(SharpTreeView))); |
||||
|
||||
SelectionModeProperty.OverrideMetadata(typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(SelectionMode.Extended)); |
||||
|
||||
AlternationCountProperty.OverrideMetadata(typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(2)); |
||||
|
||||
DefaultItemContainerStyleKey = |
||||
new ComponentResourceKey(typeof(SharpTreeView), "DefaultItemContainerStyleKey"); |
||||
|
||||
VirtualizingStackPanel.VirtualizationModeProperty.OverrideMetadata(typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(VirtualizationMode.Recycling)); |
||||
} |
||||
|
||||
public static ResourceKey DefaultItemContainerStyleKey { get; private set; } |
||||
|
||||
public SharpTreeView() |
||||
{ |
||||
SetResourceReference(ItemContainerStyleProperty, DefaultItemContainerStyleKey); |
||||
} |
||||
|
||||
public static readonly DependencyProperty RootProperty = |
||||
DependencyProperty.Register("Root", typeof(SharpTreeNode), typeof(SharpTreeView)); |
||||
|
||||
public SharpTreeNode Root |
||||
{ |
||||
get { return (SharpTreeNode)GetValue(RootProperty); } |
||||
set { SetValue(RootProperty, value); } |
||||
} |
||||
|
||||
public static readonly DependencyProperty ShowRootProperty = |
||||
DependencyProperty.Register("ShowRoot", typeof(bool), typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(true)); |
||||
|
||||
public bool ShowRoot |
||||
{ |
||||
get { return (bool)GetValue(ShowRootProperty); } |
||||
set { SetValue(ShowRootProperty, value); } |
||||
} |
||||
|
||||
public static readonly DependencyProperty ShowRootExpanderProperty = |
||||
DependencyProperty.Register("ShowRootExpander", typeof(bool), typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(false)); |
||||
|
||||
public bool ShowRootExpander |
||||
{ |
||||
get { return (bool)GetValue(ShowRootExpanderProperty); } |
||||
set { SetValue(ShowRootExpanderProperty, value); } |
||||
} |
||||
|
||||
public static readonly DependencyProperty AllowDropOrderProperty = |
||||
DependencyProperty.Register("AllowDropOrder", typeof(bool), typeof(SharpTreeView)); |
||||
|
||||
public bool AllowDropOrder |
||||
{ |
||||
get { return (bool)GetValue(AllowDropOrderProperty); } |
||||
set { SetValue(AllowDropOrderProperty, value); } |
||||
} |
||||
|
||||
public static readonly DependencyProperty ShowLinesProperty = |
||||
DependencyProperty.Register("ShowLines", typeof(bool), typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(true)); |
||||
|
||||
public bool ShowLines |
||||
{ |
||||
get { return (bool)GetValue(ShowLinesProperty); } |
||||
set { SetValue(ShowLinesProperty, value); } |
||||
} |
||||
|
||||
public static bool GetShowAlternation(DependencyObject obj) |
||||
{ |
||||
return (bool)obj.GetValue(ShowAlternationProperty); |
||||
} |
||||
|
||||
public static void SetShowAlternation(DependencyObject obj, bool value) |
||||
{ |
||||
obj.SetValue(ShowAlternationProperty, value); |
||||
} |
||||
|
||||
public static readonly DependencyProperty ShowAlternationProperty = |
||||
DependencyProperty.RegisterAttached("ShowAlternation", typeof(bool), typeof(SharpTreeView), |
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits)); |
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) |
||||
{ |
||||
base.OnPropertyChanged(e); |
||||
if (e.Property == RootProperty || |
||||
e.Property == ShowRootProperty || |
||||
e.Property == ShowRootExpanderProperty) { |
||||
Reload(); |
||||
} |
||||
} |
||||
|
||||
TreeFlattener flattener; |
||||
|
||||
void Reload() |
||||
{ |
||||
if (flattener != null) { |
||||
flattener.Stop(); |
||||
} |
||||
if (Root != null) { |
||||
if (!(ShowRoot && ShowRootExpander)) { |
||||
Root.IsExpanded = true; |
||||
} |
||||
flattener = new TreeFlattener(Root, ShowRoot); |
||||
ItemsSource = flattener.List; |
||||
flattener.Start(); |
||||
} |
||||
} |
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() |
||||
{ |
||||
return new SharpTreeViewItem(); |
||||
} |
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) |
||||
{ |
||||
return item is SharpTreeViewItem; |
||||
} |
||||
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item) |
||||
{ |
||||
base.PrepareContainerForItemOverride(element, item); |
||||
SharpTreeViewItem container = element as SharpTreeViewItem; |
||||
container.ParentTreeView = this; |
||||
} |
||||
|
||||
internal void HandleCollapsing(SharpTreeNode Node) |
||||
{ |
||||
var selectedChilds = Node.Descendants().Where(n => SharpTreeNode.SelectedNodes.Contains(n)); |
||||
if (selectedChilds.Any()) { |
||||
var list = SelectedItems.Cast<SharpTreeNode>().Except(selectedChilds).ToList(); |
||||
list.AddOnce(Node); |
||||
SetSelectedItems(list); |
||||
} |
||||
} |
||||
|
||||
#region Track selection
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e) |
||||
{ |
||||
foreach (SharpTreeNode node in e.RemovedItems) { |
||||
SharpTreeNode.SelectedNodes.Remove(node); |
||||
} |
||||
foreach (SharpTreeNode node in e.AddedItems) { |
||||
SharpTreeNode.SelectedNodes.AddOnce(node); |
||||
} |
||||
|
||||
if (IsKeyboardFocusWithin) { |
||||
foreach (SharpTreeNode node in e.RemovedItems) { |
||||
SharpTreeNode.ActiveNodes.Remove(node); |
||||
} |
||||
foreach (SharpTreeNode node in e.AddedItems) { |
||||
SharpTreeNode.ActiveNodes.AddOnce(node); |
||||
} |
||||
SortActiveNodes(); |
||||
} |
||||
base.OnSelectionChanged(e); |
||||
} |
||||
|
||||
protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e) |
||||
{ |
||||
foreach (SharpTreeNode node in SelectedItems) { |
||||
SharpTreeNode.ActiveNodes.AddOnce(node); |
||||
} |
||||
SortActiveNodes(); |
||||
} |
||||
|
||||
protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e) |
||||
{ |
||||
foreach (SharpTreeNode node in SelectedItems) { |
||||
SharpTreeNode.ActiveNodes.Remove(node); |
||||
} |
||||
} |
||||
|
||||
void SortActiveNodes() |
||||
{ |
||||
SharpTreeNode.ActiveNodes.Sort(delegate(SharpTreeNode n1, SharpTreeNode n2) { |
||||
var index1 = Items.IndexOf(n1); |
||||
var index2 = Items.IndexOf(n2); |
||||
return index1.CompareTo(index2); |
||||
}); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Drag and Drop
|
||||
|
||||
protected override void OnDragEnter(DragEventArgs e) |
||||
{ |
||||
OnDragOver(e); |
||||
} |
||||
|
||||
protected override void OnDragOver(DragEventArgs e) |
||||
{ |
||||
e.Effects = DragDropEffects.None; |
||||
e.Handled = true; |
||||
|
||||
if (Root != null && !ShowRoot && Root.Children.Count == 0) { |
||||
Root.InternalCanDrop(e, 0); |
||||
} |
||||
} |
||||
|
||||
protected override void OnDrop(DragEventArgs e) |
||||
{ |
||||
e.Effects = DragDropEffects.None; |
||||
e.Handled = true; |
||||
|
||||
if (Root != null && !ShowRoot && Root.Children.Count == 0) { |
||||
Root.InternalDrop(e, 0); |
||||
} |
||||
} |
||||
|
||||
internal void HandleDragEnter(SharpTreeViewItem item, DragEventArgs e) |
||||
{ |
||||
HandleDragOver(item, e); |
||||
} |
||||
|
||||
internal void HandleDragOver(SharpTreeViewItem item, DragEventArgs e) |
||||
{ |
||||
HidePreview(); |
||||
e.Handled = true; |
||||
|
||||
var target = GetDropTarget(item, e); |
||||
if (target != null) { |
||||
ShowPreview(target.Item, target.Place); |
||||
} |
||||
} |
||||
|
||||
internal void HandleDrop(SharpTreeViewItem item, DragEventArgs e) |
||||
{ |
||||
HidePreview(); |
||||
e.Handled = true; |
||||
|
||||
var target = GetDropTarget(item, e); |
||||
if (target != null) { |
||||
target.Node.InternalDrop(e, target.Index); |
||||
} |
||||
} |
||||
|
||||
internal void HandleDragLeave(SharpTreeViewItem item, DragEventArgs e) |
||||
{ |
||||
HidePreview(); |
||||
e.Handled = true; |
||||
} |
||||
|
||||
class DropTarget |
||||
{ |
||||
public SharpTreeViewItem Item; |
||||
public DropPlace Place; |
||||
public double Y; |
||||
public SharpTreeNode Node; |
||||
public int Index; |
||||
} |
||||
|
||||
DropTarget GetDropTarget(SharpTreeViewItem item, DragEventArgs e) |
||||
{ |
||||
var dropTargets = BuildDropTargets(item, e); |
||||
var y = e.GetPosition(item).Y; |
||||
foreach (var target in dropTargets) { |
||||
if (target.Y >= y) { |
||||
return target; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
List<DropTarget> BuildDropTargets(SharpTreeViewItem item, DragEventArgs e) |
||||
{ |
||||
var result = new List<DropTarget>(); |
||||
var node = item.Node; |
||||
|
||||
if (AllowDropOrder) { |
||||
TryAddDropTarget(result, item, DropPlace.Before, e); |
||||
} |
||||
|
||||
TryAddDropTarget(result, item, DropPlace.Inside, e); |
||||
|
||||
if (AllowDropOrder) { |
||||
if (node.IsExpanded && node.Children.Count > 0) { |
||||
var firstChildItem = ItemContainerGenerator.ContainerFromItem(node.Children[0]) as SharpTreeViewItem; |
||||
TryAddDropTarget(result, firstChildItem, DropPlace.Before, e); |
||||
} |
||||
else { |
||||
TryAddDropTarget(result, item, DropPlace.After, e); |
||||
} |
||||
} |
||||
|
||||
var h = item.ActualHeight; |
||||
var y1 = 0.2 * h; |
||||
var y2 = h / 2; |
||||
var y3 = h - y1; |
||||
|
||||
if (result.Count == 2) { |
||||
if (result[0].Place == DropPlace.Inside && |
||||
result[1].Place != DropPlace.Inside) { |
||||
result[0].Y = y3; |
||||
} |
||||
else if (result[0].Place != DropPlace.Inside && |
||||
result[1].Place == DropPlace.Inside) { |
||||
result[0].Y = y1; |
||||
} |
||||
else { |
||||
result[0].Y = y2; |
||||
} |
||||
} |
||||
else if (result.Count == 3) { |
||||
result[0].Y = y1; |
||||
result[1].Y = y3; |
||||
} |
||||
if (result.Count > 0) { |
||||
result[result.Count - 1].Y = h; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
void TryAddDropTarget(List<DropTarget> targets, SharpTreeViewItem item, DropPlace place, DragEventArgs e) |
||||
{ |
||||
SharpTreeNode node; |
||||
int index; |
||||
|
||||
GetNodeAndIndex(item, place, out node, out index); |
||||
|
||||
if (node != null) { |
||||
e.Effects = DragDropEffects.None; |
||||
if (node.InternalCanDrop(e, index)) { |
||||
DropTarget target = new DropTarget() { |
||||
Item = item, |
||||
Place = place, |
||||
Node = node, |
||||
Index = index |
||||
}; |
||||
targets.Add(target); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void GetNodeAndIndex(SharpTreeViewItem item, DropPlace place, out SharpTreeNode node, out int index) |
||||
{ |
||||
node = null; |
||||
index = 0; |
||||
|
||||
if (place == DropPlace.Inside) { |
||||
node = item.Node; |
||||
index = node.Children.Count; |
||||
} |
||||
else if (place == DropPlace.Before) { |
||||
if (item.Node.Parent != null) { |
||||
node = item.Node.Parent; |
||||
index = node.Children.IndexOf(item.Node); |
||||
} |
||||
} |
||||
else { |
||||
if (item.Node.Parent != null) { |
||||
node = item.Node.Parent; |
||||
index = node.Children.IndexOf(item.Node) + 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
SharpTreeNodeView previewNodeView; |
||||
InsertMarker insertMarker; |
||||
DropPlace previewPlace; |
||||
|
||||
enum DropPlace |
||||
{ |
||||
Before, Inside, After |
||||
} |
||||
|
||||
void ShowPreview(SharpTreeViewItem item, DropPlace place) |
||||
{ |
||||
previewNodeView = item.NodeView; |
||||
previewPlace = place; |
||||
|
||||
if (place == DropPlace.Inside) { |
||||
previewNodeView.TextBackground = SystemColors.HighlightBrush; |
||||
previewNodeView.Foreground = SystemColors.HighlightTextBrush; |
||||
} |
||||
else { |
||||
if (insertMarker == null) { |
||||
var adornerLayer = AdornerLayer.GetAdornerLayer(this); |
||||
var adorner = new GeneralAdorner(this); |
||||
insertMarker = new InsertMarker(); |
||||
adorner.Child = insertMarker; |
||||
adornerLayer.Add(adorner); |
||||
} |
||||
|
||||
insertMarker.Visibility = Visibility.Visible; |
||||
|
||||
var p1 = previewNodeView.TransformToVisual(this).Transform(new Point()); |
||||
var p = new Point(p1.X + previewNodeView.CalculateIndent() + 4.5, p1.Y - 3); |
||||
|
||||
if (place == DropPlace.After) { |
||||
p.Y += previewNodeView.ActualHeight; |
||||
} |
||||
|
||||
insertMarker.Margin = new Thickness(p.X, p.Y, 0, 0); |
||||
|
||||
SharpTreeNodeView secondNodeView = null; |
||||
var index = flattener.List.IndexOf(item.Node); |
||||
|
||||
if (place == DropPlace.Before) { |
||||
if (index > 0) { |
||||
secondNodeView = (ItemContainerGenerator.ContainerFromIndex(index - 1) as SharpTreeViewItem).NodeView; |
||||
} |
||||
} |
||||
else if (index + 1 < flattener.List.Count) { |
||||
secondNodeView = (ItemContainerGenerator.ContainerFromIndex(index + 1) as SharpTreeViewItem).NodeView; |
||||
} |
||||
|
||||
var w = p1.X + previewNodeView.ActualWidth - p.X; |
||||
|
||||
if (secondNodeView != null) { |
||||
var p2 = secondNodeView.TransformToVisual(this).Transform(new Point()); |
||||
w = Math.Max(w, p2.X + secondNodeView.ActualWidth - p.X); |
||||
} |
||||
|
||||
insertMarker.Width = w + 10; |
||||
} |
||||
} |
||||
|
||||
void HidePreview() |
||||
{ |
||||
if (previewNodeView != null) { |
||||
previewNodeView.ClearValue(SharpTreeNodeView.TextBackgroundProperty); |
||||
previewNodeView.ClearValue(SharpTreeNodeView.ForegroundProperty); |
||||
if (insertMarker != null) { |
||||
insertMarker.Visibility = Visibility.Collapsed; |
||||
} |
||||
previewNodeView = null; |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,195 @@
@@ -0,0 +1,195 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Windows.Controls; |
||||
using System.Windows; |
||||
using System.Windows.Media; |
||||
using System.Windows.Input; |
||||
using System.Diagnostics; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
public class SharpTreeViewItem : ListViewItem |
||||
{ |
||||
static SharpTreeViewItem() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(SharpTreeViewItem), |
||||
new FrameworkPropertyMetadata(typeof(SharpTreeViewItem))); |
||||
|
||||
RegisterCommands(); |
||||
} |
||||
|
||||
public SharpTreeNode Node |
||||
{ |
||||
get { return DataContext as SharpTreeNode; } |
||||
} |
||||
|
||||
public SharpTreeNodeView NodeView { get; internal set; } |
||||
public SharpTreeView ParentTreeView { get; internal set; } |
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e) |
||||
{ |
||||
switch (e.Key) { |
||||
case Key.F2: |
||||
if (SharpTreeNode.ActiveNodes.Count == 1 && Node.IsEditable) { |
||||
Node.IsEditing = true; |
||||
} |
||||
break; |
||||
case Key.Escape: |
||||
Node.IsEditing = false; |
||||
break; |
||||
case Key.Left: |
||||
Node.IsExpanded = false; |
||||
break; |
||||
case Key.Right: |
||||
Node.IsExpanded = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
protected override void OnContextMenuOpening(ContextMenuEventArgs e) |
||||
{ |
||||
ContextMenu = Node.GetContextMenu(); |
||||
} |
||||
|
||||
protected override void OnContextMenuClosing(ContextMenuEventArgs e) |
||||
{ |
||||
ClearValue(ContextMenuProperty); |
||||
} |
||||
|
||||
#region Mouse
|
||||
|
||||
Point startPoint; |
||||
bool wasSelected; |
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) |
||||
{ |
||||
wasSelected = IsSelected; |
||||
if (!IsSelected) { |
||||
base.OnMouseLeftButtonDown(e); |
||||
} |
||||
|
||||
if (Mouse.LeftButton == MouseButtonState.Pressed) { |
||||
startPoint = e.GetPosition(null); |
||||
CaptureMouse(); |
||||
|
||||
if (e.ClickCount == 2) { |
||||
if (!Node.IsRoot || ParentTreeView.ShowRootExpander) { |
||||
Node.IsExpanded = !Node.IsExpanded; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e) |
||||
{ |
||||
if (IsMouseCaptured) { |
||||
var currentPoint = e.GetPosition(null); |
||||
if (Math.Abs(currentPoint.X - startPoint.X) >= SystemParameters.MinimumHorizontalDragDistance || |
||||
Math.Abs(currentPoint.Y - startPoint.Y) >= SystemParameters.MinimumVerticalDragDistance) { |
||||
|
||||
if (Node.InternalCanDrag()) { |
||||
Node.InternalDrag(this); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) |
||||
{ |
||||
ReleaseMouseCapture(); |
||||
if (wasSelected) { |
||||
base.OnMouseLeftButtonDown(e); |
||||
} |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Drag and Drop
|
||||
|
||||
protected override void OnDragEnter(DragEventArgs e) |
||||
{ |
||||
ParentTreeView.HandleDragEnter(this, e); |
||||
} |
||||
|
||||
protected override void OnDragOver(DragEventArgs e) |
||||
{ |
||||
ParentTreeView.HandleDragOver(this, e); |
||||
} |
||||
|
||||
protected override void OnDrop(DragEventArgs e) |
||||
{ |
||||
ParentTreeView.HandleDrop(this, e); |
||||
} |
||||
|
||||
protected override void OnDragLeave(DragEventArgs e) |
||||
{ |
||||
ParentTreeView.HandleDragLeave(this, e); |
||||
} |
||||
|
||||
#endregion
|
||||
|
||||
#region Cut / Copy / Paste / Delete Commands
|
||||
|
||||
static void RegisterCommands() |
||||
{ |
||||
CommandManager.RegisterClassCommandBinding(typeof(SharpTreeViewItem), |
||||
new CommandBinding(ApplicationCommands.Cut, HandleExecuted_Cut, HandleCanExecute_Cut)); |
||||
|
||||
CommandManager.RegisterClassCommandBinding(typeof(SharpTreeViewItem), |
||||
new CommandBinding(ApplicationCommands.Copy, HandleExecuted_Copy, HandleCanExecute_Copy)); |
||||
|
||||
CommandManager.RegisterClassCommandBinding(typeof(SharpTreeViewItem), |
||||
new CommandBinding(ApplicationCommands.Paste, HandleExecuted_Paste, HandleCanExecute_Paste)); |
||||
|
||||
CommandManager.RegisterClassCommandBinding(typeof(SharpTreeViewItem), |
||||
new CommandBinding(ApplicationCommands.Delete, HandleExecuted_Delete, HandleCanExecute_Delete)); |
||||
} |
||||
|
||||
static void HandleExecuted_Cut(object sender, ExecutedRoutedEventArgs e) |
||||
{ |
||||
(sender as SharpTreeViewItem).Node.InternalCut(); |
||||
} |
||||
|
||||
static void HandleCanExecute_Cut(object sender, CanExecuteRoutedEventArgs e) |
||||
{ |
||||
e.CanExecute = (sender as SharpTreeViewItem).Node.InternalCanCut(); |
||||
} |
||||
|
||||
static void HandleExecuted_Copy(object sender, ExecutedRoutedEventArgs e) |
||||
{ |
||||
(sender as SharpTreeViewItem).Node.InternalCopy(); |
||||
} |
||||
|
||||
static void HandleCanExecute_Copy(object sender, CanExecuteRoutedEventArgs e) |
||||
{ |
||||
e.CanExecute = (sender as SharpTreeViewItem).Node.InternalCanCopy(); |
||||
} |
||||
|
||||
static void HandleExecuted_Paste(object sender, ExecutedRoutedEventArgs e) |
||||
{ |
||||
(sender as SharpTreeViewItem).Node.InternalPaste(); |
||||
} |
||||
|
||||
static void HandleCanExecute_Paste(object sender, CanExecuteRoutedEventArgs e) |
||||
{ |
||||
e.CanExecute = (sender as SharpTreeViewItem).Node.InternalCanPaste(); |
||||
} |
||||
|
||||
static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e) |
||||
{ |
||||
(sender as SharpTreeViewItem).Node.InternalDelete(); |
||||
} |
||||
|
||||
static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e) |
||||
{ |
||||
e.CanExecute = (sender as SharpTreeViewItem).Node.InternalCanDelete(); |
||||
} |
||||
|
||||
#endregion
|
||||
} |
||||
} |
@ -0,0 +1,312 @@
@@ -0,0 +1,312 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
xmlns:Default="clr-namespace:ICSharpCode.TreeView"> |
||||
|
||||
<SolidColorBrush x:Key="ListBorder" |
||||
Color="#FF7F9DB9" /> |
||||
|
||||
<Style x:Key="ExpandCollapseToggleStyle" |
||||
TargetType="{x:Type ToggleButton}"> |
||||
<Setter Property="Focusable" |
||||
Value="False" /> |
||||
<Setter Property="Template"> |
||||
<Setter.Value> |
||||
<ControlTemplate TargetType="{x:Type ToggleButton}"> |
||||
<Border Width="9" |
||||
Height="9" |
||||
BorderThickness="1" |
||||
BorderBrush="#FF7898B5" |
||||
CornerRadius="1" |
||||
SnapsToDevicePixels="True"> |
||||
<Border.Background> |
||||
<LinearGradientBrush StartPoint="0,0" |
||||
EndPoint="1,1"> |
||||
<LinearGradientBrush.GradientStops> |
||||
<GradientStop Color="White" |
||||
Offset=".2" /> |
||||
<GradientStop Color="#FFC0B7A6" |
||||
Offset="1" /> |
||||
</LinearGradientBrush.GradientStops> |
||||
</LinearGradientBrush> |
||||
</Border.Background> |
||||
<Path Name="ExpandPath" |
||||
Margin="1,1,1,1" |
||||
Fill="Black" |
||||
Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z" /> |
||||
</Border> |
||||
<ControlTemplate.Triggers> |
||||
<Trigger Property="IsChecked" |
||||
Value="True"> |
||||
<Setter Property="Data" |
||||
TargetName="ExpandPath" |
||||
Value="M 0 2 L 0 3 L 5 3 L 5 2 Z" /> |
||||
</Trigger> |
||||
</ControlTemplate.Triggers> |
||||
</ControlTemplate> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
|
||||
<Style TargetType="{x:Type Default:InsertMarker}"> |
||||
<Setter Property="IsHitTestVisible" |
||||
Value="False" /> |
||||
<Setter Property="Template"> |
||||
<Setter.Value> |
||||
<ControlTemplate TargetType="{x:Type Default:InsertMarker}"> |
||||
<Grid> |
||||
<Border VerticalAlignment="Center" |
||||
Height="2" |
||||
Background="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> |
||||
<Path Data="m 0 0 l 3 3 l -3 3" |
||||
Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" |
||||
HorizontalAlignment="Left" /> |
||||
<Path Data="m 0 0 l -3 3 l 3 3" |
||||
Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" |
||||
HorizontalAlignment="Right" /> |
||||
</Grid> |
||||
</ControlTemplate> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
|
||||
<Style TargetType="{x:Type Default:EditTextBox}"> |
||||
<Setter Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" /> |
||||
<Setter Property="KeyboardNavigation.TabNavigation" |
||||
Value="None" /> |
||||
<Setter Property="HorizontalContentAlignment" |
||||
Value="Left" /> |
||||
<Setter Property="FocusVisualStyle" |
||||
Value="{x:Null}" /> |
||||
<Setter Property="AllowDrop" |
||||
Value="True" /> |
||||
<Setter Property="Template"> |
||||
<Setter.Value> |
||||
<ControlTemplate TargetType="{x:Type Default:EditTextBox}"> |
||||
<Border Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" |
||||
BorderThickness="1" |
||||
BorderBrush="{StaticResource ListBorder}" |
||||
Padding="0 1 2 0"> |
||||
<ScrollViewer Name="PART_ContentHost" /> |
||||
</Border> |
||||
</ControlTemplate> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
|
||||
<Style TargetType="{x:Type Default:SharpTreeView}" |
||||
BasedOn="{StaticResource {x:Type ListBox}}"> |
||||
<Style.Triggers> |
||||
<Trigger Property="ShowRoot" |
||||
Value="False"> |
||||
<Setter Property="Padding" |
||||
Value="5 0 0 0" /> |
||||
</Trigger> |
||||
</Style.Triggers> |
||||
</Style> |
||||
|
||||
<Style x:Key="{x:Static Default:SharpTreeView.DefaultItemContainerStyleKey}" |
||||
TargetType="{x:Type Default:SharpTreeViewItem}"> |
||||
<Style.Triggers> |
||||
<MultiTrigger> |
||||
<MultiTrigger.Conditions> |
||||
<Condition Property="ItemsControl.AlternationIndex" |
||||
Value="1" /> |
||||
<Condition Property="Default:SharpTreeView.ShowAlternation" |
||||
Value="True" /> |
||||
</MultiTrigger.Conditions> |
||||
<Setter Property="Background" |
||||
Value="WhiteSmoke" /> |
||||
</MultiTrigger> |
||||
</Style.Triggers> |
||||
</Style> |
||||
|
||||
<Style x:Key="{x:Static Default:SharpGridView.ItemContainerStyleKey}" |
||||
TargetType="{x:Type ListViewItem}"> |
||||
<Setter Property="Background" |
||||
Value="Transparent" /> |
||||
<Setter Property="VerticalContentAlignment" |
||||
Value="Center" /> |
||||
<Setter Property="Template"> |
||||
<Setter.Value> |
||||
<ControlTemplate TargetType="{x:Type ListViewItem}"> |
||||
<Border Name="Bd" |
||||
Background="{TemplateBinding Background}" |
||||
BorderBrush="{TemplateBinding BorderBrush}" |
||||
BorderThickness="{TemplateBinding BorderThickness}" |
||||
Padding="{TemplateBinding Padding}" |
||||
SnapsToDevicePixels="true"> |
||||
<GridViewRowPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}" |
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" /> |
||||
</Border> |
||||
<ControlTemplate.Triggers> |
||||
<Trigger Property="IsSelected" |
||||
Value="true"> |
||||
<Setter TargetName="Bd" |
||||
Property="Background" |
||||
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> |
||||
<Setter Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" /> |
||||
</Trigger> |
||||
<MultiTrigger> |
||||
<MultiTrigger.Conditions> |
||||
<Condition Property="IsSelected" |
||||
Value="true" /> |
||||
<Condition Property="Selector.IsSelectionActive" |
||||
Value="false" /> |
||||
</MultiTrigger.Conditions> |
||||
<Setter TargetName="Bd" |
||||
Property="Background" |
||||
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" /> |
||||
<Setter Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" /> |
||||
</MultiTrigger> |
||||
<Trigger Property="IsEnabled" |
||||
Value="false"> |
||||
<Setter Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" /> |
||||
</Trigger> |
||||
</ControlTemplate.Triggers> |
||||
</ControlTemplate> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
|
||||
<Style TargetType="{x:Type Default:SharpTreeViewItem}"> |
||||
<Setter Property="FocusVisualStyle" |
||||
Value="{x:Null}" /> |
||||
<Setter Property="Template"> |
||||
<Setter.Value> |
||||
<ControlTemplate TargetType="{x:Type Default:SharpTreeViewItem}"> |
||||
<Border Background="Transparent"> |
||||
<Border Background="{TemplateBinding Background}"> |
||||
<Default:SharpTreeNodeView Name="nodeView" |
||||
HorizontalAlignment="Left" /> |
||||
</Border> |
||||
</Border> |
||||
<ControlTemplate.Triggers> |
||||
<Trigger Property="IsSelected" |
||||
Value="True"> |
||||
<Setter TargetName="nodeView" |
||||
Property="TextBackground" |
||||
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> |
||||
<Setter TargetName="nodeView" |
||||
Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" /> |
||||
</Trigger> |
||||
<!--<MultiTrigger> |
||||
<MultiTrigger.Conditions> |
||||
<Condition Property="IsSelected" |
||||
Value="True" /> |
||||
<Condition Property="Selector.IsSelectionActive" |
||||
Value="False" /> |
||||
</MultiTrigger.Conditions> |
||||
<Setter TargetName="nodeView" |
||||
Property="TextBackground" |
||||
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" /> |
||||
<Setter TargetName="nodeView" |
||||
Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" /> |
||||
</MultiTrigger>--> |
||||
<Trigger Property="IsEnabled" |
||||
Value="False"> |
||||
<Setter Property="Foreground" |
||||
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" /> |
||||
</Trigger> |
||||
</ControlTemplate.Triggers> |
||||
</ControlTemplate> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
|
||||
<Style TargetType="{x:Type Default:SharpTreeNodeView}"> |
||||
<Setter Property="Focusable" |
||||
Value="False" /> |
||||
<Setter Property="Template"> |
||||
<Setter.Value> |
||||
<ControlTemplate TargetType="{x:Type Default:SharpTreeNodeView}"> |
||||
<Grid> |
||||
<Default:LinesRenderer Name="linesRenderer" |
||||
ClipToBounds="True" |
||||
Visibility="{Binding ShowLines, RelativeSource={RelativeSource AncestorType={x:Type Default:SharpTreeView}}, Converter={Default:CollapsedWhenFalse}}" /> |
||||
<StackPanel Orientation="Horizontal"> |
||||
<FrameworkElement Name="spacer" /> |
||||
<ToggleButton Name="expander" |
||||
Style="{StaticResource ExpandCollapseToggleStyle}" |
||||
IsChecked="{Binding IsExpanded}" |
||||
Visibility="Hidden" |
||||
Margin="0 0 6 0" |
||||
VerticalAlignment="Center" /> |
||||
<Border Name="checkBoxContainer" |
||||
Width="16" |
||||
Margin="0 0 3 0" |
||||
Visibility="Collapsed"> |
||||
<CheckBox IsChecked="{Binding IsChecked}" |
||||
HorizontalAlignment="Center" |
||||
VerticalAlignment="Center" /> |
||||
</Border> |
||||
<StackPanel Orientation="Horizontal" |
||||
Background="Transparent" |
||||
ToolTip="{Binding ToolTip}"> |
||||
<ContentControl Name="icon" |
||||
Content="{Binding Icon}" |
||||
Width="16" |
||||
Height="16" |
||||
Margin="0 0 5 1" |
||||
VerticalAlignment="Center" |
||||
Focusable="False" /> |
||||
<Border Name="textContainer" |
||||
Background="{TemplateBinding TextBackground}"> |
||||
<ContentControl Content="{Binding Text}" |
||||
Margin="2 0 6 0" |
||||
VerticalAlignment="Center" |
||||
Focusable="False" /> |
||||
</Border> |
||||
<Border Name="textEditorContainer" /> |
||||
</StackPanel> |
||||
</StackPanel> |
||||
</Grid> |
||||
<ControlTemplate.Triggers> |
||||
<DataTrigger Binding="{Binding IsEditing}" |
||||
Value="True"> |
||||
<Setter TargetName="textContainer" |
||||
Property="Visibility" |
||||
Value="Collapsed" /> |
||||
</DataTrigger> |
||||
<DataTrigger Binding="{Binding ShowIcon}" |
||||
Value="False"> |
||||
<Setter TargetName="icon" |
||||
Property="Visibility" |
||||
Value="Collapsed" /> |
||||
</DataTrigger> |
||||
<DataTrigger Binding="{Binding IsExpanded}" |
||||
Value="True"> |
||||
<Setter TargetName="icon" |
||||
Property="Content" |
||||
Value="{Binding ExpandedIcon}" /> |
||||
</DataTrigger> |
||||
<DataTrigger Binding="{Binding ShowExpander}" |
||||
Value="True"> |
||||
<Setter TargetName="expander" |
||||
Property="Visibility" |
||||
Value="Visible" /> |
||||
</DataTrigger> |
||||
<DataTrigger Binding="{Binding IsCheckable}" |
||||
Value="True"> |
||||
<Setter TargetName="checkBoxContainer" |
||||
Property="Visibility" |
||||
Value="Visible" /> |
||||
</DataTrigger> |
||||
<DataTrigger Binding="{Binding IsCut}" |
||||
Value="True"> |
||||
<Setter TargetName="icon" |
||||
Property="Opacity" |
||||
Value="0.5" /> |
||||
</DataTrigger> |
||||
</ControlTemplate.Triggers> |
||||
</ControlTemplate> |
||||
</Setter.Value> |
||||
</Setter> |
||||
</Style> |
||||
|
||||
</ResourceDictionary> |
@ -0,0 +1,150 @@
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Text; |
||||
using System.Collections.ObjectModel; |
||||
using System.ComponentModel; |
||||
using System.Collections.Specialized; |
||||
|
||||
namespace ICSharpCode.TreeView |
||||
{ |
||||
class TreeFlattener |
||||
{ |
||||
public TreeFlattener(SharpTreeNode root, bool includeRoot) |
||||
{ |
||||
this.root = root; |
||||
this.includeRoot = includeRoot; |
||||
List = new ObservableCollection<SharpTreeNode>(); |
||||
} |
||||
|
||||
SharpTreeNode root; |
||||
bool includeRoot; |
||||
|
||||
public ObservableCollection<SharpTreeNode> List { get; private set; } |
||||
|
||||
public void Start() |
||||
{ |
||||
if (includeRoot) { |
||||
Add(root); |
||||
} |
||||
else { |
||||
root.Children.CollectionChanged += node_ChildrenChanged; |
||||
} |
||||
|
||||
foreach (var node in root.ExpandedDescendants()) { |
||||
Add(node); |
||||
} |
||||
} |
||||
|
||||
public void Stop() |
||||
{ |
||||
while (List.Count > 0) { |
||||
RemoveAt(0); |
||||
} |
||||
} |
||||
|
||||
void Add(SharpTreeNode node) |
||||
{ |
||||
Insert(List.Count, node); |
||||
} |
||||
|
||||
void Insert(int index, SharpTreeNode node) |
||||
{ |
||||
List.Insert(index, node); |
||||
node.PropertyChanged += node_PropertyChanged; |
||||
if (node.IsExpanded) { |
||||
node.Children.CollectionChanged += node_ChildrenChanged; |
||||
} |
||||
} |
||||
|
||||
void RemoveAt(int index) |
||||
{ |
||||
var node = List[index]; |
||||
List.RemoveAt(index); |
||||
node.PropertyChanged -= node_PropertyChanged; |
||||
if (node.IsExpanded) { |
||||
node.Children.CollectionChanged -= node_ChildrenChanged; |
||||
} |
||||
} |
||||
|
||||
void ClearDescendants(SharpTreeNode node) |
||||
{ |
||||
var index = List.IndexOf(node); |
||||
while (index + 1 < List.Count && List[index + 1].Level > node.Level) { |
||||
RemoveAt(index + 1); |
||||
} |
||||
} |
||||
|
||||
void node_PropertyChanged(object sender, PropertyChangedEventArgs e) |
||||
{ |
||||
if (e.PropertyName == "IsExpanded") { |
||||
var node = sender as SharpTreeNode; |
||||
|
||||
if (node.IsExpanded) { |
||||
var index = List.IndexOf(node); |
||||
foreach (var childNode in node.ExpandedDescendants()) { |
||||
Insert(++index, childNode); |
||||
} |
||||
node.Children.CollectionChanged += node_ChildrenChanged; |
||||
} |
||||
else { |
||||
ClearDescendants(node); |
||||
node.Children.CollectionChanged -= node_ChildrenChanged; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Insert(SharpTreeNode parent, int index, SharpTreeNode node) |
||||
{ |
||||
int finalIndex = 0; |
||||
if (index > 0) { |
||||
finalIndex = List.IndexOf(parent.Children[index - 1]) + 1; |
||||
while (finalIndex < List.Count && List[finalIndex].Level > node.Level) { |
||||
finalIndex++; |
||||
} |
||||
} |
||||
else { |
||||
finalIndex = List.IndexOf(parent) + 1; |
||||
} |
||||
Insert(finalIndex, node); |
||||
} |
||||
|
||||
void RemoveAt(SharpTreeNode parent, int index, SharpTreeNode node) |
||||
{ |
||||
var i = List.IndexOf(node); |
||||
foreach (var child in node.ExpandedDescendantsAndSelf()) { |
||||
RemoveAt(i); |
||||
} |
||||
} |
||||
|
||||
void node_ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
{ |
||||
var collection = sender as SharpTreeNodeCollection; |
||||
var parent = collection.Parent; |
||||
var index = List.IndexOf(collection.Parent) + 1; |
||||
|
||||
switch (e.Action) { |
||||
case NotifyCollectionChangedAction.Add: |
||||
Insert(parent, e.NewStartingIndex, e.NewItems[0] as SharpTreeNode); |
||||
break; |
||||
case NotifyCollectionChangedAction.Remove: |
||||
RemoveAt(parent, e.OldStartingIndex, e.OldItems[0] as SharpTreeNode); |
||||
break; |
||||
case NotifyCollectionChangedAction.Move: |
||||
RemoveAt(parent, e.OldStartingIndex, e.OldItems[0] as SharpTreeNode); |
||||
Insert(parent, e.NewStartingIndex, e.NewItems[0] as SharpTreeNode); |
||||
break; |
||||
case NotifyCollectionChangedAction.Replace: |
||||
RemoveAt(parent, e.OldStartingIndex, e.OldItems[0] as SharpTreeNode); |
||||
Insert(parent, e.NewStartingIndex, e.NewItems[0] as SharpTreeNode); |
||||
break; |
||||
case NotifyCollectionChangedAction.Reset: |
||||
ClearDescendants(parent); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue