mirror of https://github.com/icsharpcode/ILSpy.git
17 changed files with 2409 additions and 0 deletions
@ -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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
<?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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
// 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 @@ |
|||||||
|
<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 @@ |
|||||||
|
// 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