Browse Source

Squashed 'SharpTreeView/' content from commit 886d615

git-subtree-dir: SharpTreeView
git-subtree-split: 886d615dc7ae9ffbe2a4f466455fd32e81547119
pull/1/head
Daniel Grunwald 14 years ago
commit
a5ac9d09ed
  1. 34
      Converters.cs
  2. 15
      DropEffect.cs
  3. 84
      EditTextBox.cs
  4. 37
      ExtensionMethods.cs
  5. 70
      GeneralAdorner.cs
  6. 93
      ICSharpCode.TreeView.csproj
  7. 21
      InsertMarker.cs
  8. 57
      LinesRenderer.cs
  9. 42
      Properties/AssemblyInfo.cs
  10. 31
      SharpGridView.cs
  11. 612
      SharpTreeNode.cs
  12. 49
      SharpTreeNodeCollection.cs
  13. 149
      SharpTreeNodeView.cs
  14. 458
      SharpTreeView.cs
  15. 195
      SharpTreeViewItem.cs
  16. 312
      Themes/Generic.xaml
  17. 150
      TreeFlattener.cs

34
Converters.cs

@ -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();
}
}
}

15
DropEffect.cs

@ -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
}
}

84
EditTextBox.cs

@ -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;
}
}
}
}

37
ExtensionMethods.cs

@ -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);
}
}
}
}

70
GeneralAdorner.cs

@ -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();
}
}
}

93
ICSharpCode.TreeView.csproj

@ -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>

21
InsertMarker.cs

@ -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)));
}
}
}

57
LinesRenderer.cs

@ -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));
}
}
}
}
}

42
Properties/AssemblyInfo.cs

@ -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")]

31
SharpGridView.cs

@ -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;
}
}
}
}

612
SharpTreeNode.cs

@ -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
}
}

49
SharpTreeNodeCollection.cs

@ -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);
}
}
}

149
SharpTreeNodeView.cs

@ -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;
}
}
}

458
SharpTreeView.cs

@ -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
}
}

195
SharpTreeViewItem.cs

@ -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
}
}

312
Themes/Generic.xaml

@ -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>

150
TreeFlattener.cs

@ -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…
Cancel
Save