first commit

This commit is contained in:
2025-04-07 07:44:27 -07:00
commit d6cde0c05e
512 changed files with 142392 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public class AutoRowHeightLayout: IRowLayout
{
private DrawContext _measureContext;
private TreeViewAdv _treeView;
private List<Rectangle> _rowCache;
public AutoRowHeightLayout(TreeViewAdv treeView, int rowHeight)
{
_rowCache = new List<Rectangle>();
_treeView = treeView;
PreferredRowHeight = rowHeight;
_measureContext = new DrawContext();
_measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1));
}
private int _rowHeight;
public int PreferredRowHeight
{
get { return _rowHeight; }
set { _rowHeight = value; }
}
public int PageRowCount
{
get
{
if (_treeView.RowCount == 0)
return 0;
else
{
int pageHeight = _treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight;
int y = 0;
for (int i = _treeView.RowCount - 1; i >= 0; i--)
{
y += GetRowHeight(i);
if (y > pageHeight)
return Math.Max(0, _treeView.RowCount - 1 - i);
}
return _treeView.RowCount;
}
}
}
public int CurrentPageSize
{
get
{
if (_treeView.RowCount == 0)
return 0;
else
{
int pageHeight = _treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight;
int y = 0;
for (int i = _treeView.FirstVisibleRow; i < _treeView.RowCount; i++)
{
y += GetRowHeight(i);
if (y > pageHeight)
return Math.Max(0, i - _treeView.FirstVisibleRow);
}
return Math.Max(0, _treeView.RowCount - _treeView.FirstVisibleRow);
}
}
}
public Rectangle GetRowBounds(int rowNo)
{
if (rowNo >= _rowCache.Count)
{
int count = _rowCache.Count;
int y = count > 0 ? _rowCache[count - 1].Bottom : 0;
for (int i = count; i <= rowNo; i++)
{
int height = GetRowHeight(i);
_rowCache.Add(new Rectangle(0, y, 0, height));
y += height;
}
if (rowNo < _rowCache.Count - 1)
return Rectangle.Empty;
}
if (rowNo >= 0 && rowNo < _rowCache.Count)
return _rowCache[rowNo];
else
return Rectangle.Empty;
}
private int GetRowHeight(int rowNo)
{
if (rowNo < _treeView.RowMap.Count)
{
TreeNodeAdv node = _treeView.RowMap[rowNo];
if (node.Height == null)
{
int res = 0;
_measureContext.Font = _treeView.Font;
foreach (NodeControl nc in _treeView.NodeControls)
{
int h = nc.GetActualSize(node, _measureContext).Height;
if (h > res)
res = h;
}
node.Height = res;
}
return node.Height.Value;
}
else
return 0;
}
public int GetRowAt(Point point)
{
int py = point.Y - _treeView.ColumnHeaderHeight;
int y = 0;
for (int i = _treeView.FirstVisibleRow; i < _treeView.RowCount; i++)
{
int h = GetRowHeight(i);
if (py >= y && py < y + h)
return i;
else
y += h;
}
return -1;
}
public int GetFirstRow(int lastPageRow)
{
int pageHeight = _treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight;
int y = 0;
for (int i = lastPageRow; i >= 0; i--)
{
y += GetRowHeight(i);
if (y > pageHeight)
return Math.Max(0, i + 1);
}
return 0;
}
public void ClearCache()
{
_rowCache.Clear();
}
}
}

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature">
<Font Name="Microsoft Sans Serif" Size="8.25" />
<Class Name="Aga.Controls.Tree.TreeModel" BaseTypeListCollapsed="true">
<Position X="0.5" Y="7" Width="3.75" />
<TypeIdentifier>
<FileName>Tree\TreeModel.cs</FileName>
<HashCode>AAAkgAAAAAAQAGQAAAAAEAAAEAACQAAAUAAAAAAAAQE=</HashCode>
</TypeIdentifier>
<Members>
<Field Name="_root" Hidden="true" />
</Members>
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
</Compartments>
<Lollipop Position="0.2" />
</Class>
<Class Name="Aga.Controls.Tree.TreePath">
<Position X="4.5" Y="4.25" Width="2" />
<TypeIdentifier>
<FileName>Tree\TreePath.cs</FileName>
<HashCode>GABAAAAAAAACAAAAAAIAAAAAAAAACAAAAAAAAAAAAAA=</HashCode>
</TypeIdentifier>
<Members>
<Field Name="_path" Hidden="true" />
<Field Name="Empty" Hidden="true" />
<Method Name="TreePath" Hidden="true" />
</Members>
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
</Compartments>
</Class>
<Class Name="Aga.Controls.Tree.Node">
<Position X="4.75" Y="7" Width="2.5" />
<TypeIdentifier>
<FileName>Tree\Node.cs</FileName>
<HashCode>AAAgABAAgCAAAAAAAgAEVAAQAAAQAAAIAAsgCAAAAAA=</HashCode>
</TypeIdentifier>
<Members>
<Field Name="_checkState" Hidden="true" />
<Field Name="_model" Hidden="true" />
<Field Name="_nodes" Hidden="true" />
<Field Name="_parent" Hidden="true" />
<Field Name="_text" Hidden="true" />
</Members>
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
</Compartments>
<NestedTypes>
<Class Name="Aga.Controls.Tree.Node.NodeCollection" Collapsed="true">
<TypeIdentifier>
<NewMemberFileName>Tree\Node.cs</NewMemberFileName>
</TypeIdentifier>
</Class>
</NestedTypes>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeControl">
<Position X="0.5" Y="0.5" Width="3.75" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeControl.cs</FileName>
<HashCode>AAAAAAAAgAAAgsIAAAhAQAAwAAAAEAAAAEAIAAAAAAA=</HashCode>
</TypeIdentifier>
<Members>
<Field Name="_column" Hidden="true" />
<Field Name="_parent" Hidden="true" />
<Field Name="_toolTipProvider" Hidden="true" />
<Method Name="AssignParent" Hidden="true" />
</Members>
</Class>
<Interface Name="Aga.Controls.Tree.ITreeModel">
<Position X="0.5" Y="4.25" Width="3.5" />
<TypeIdentifier>
<FileName>Tree\ITreeModel.cs</FileName>
<HashCode>AAAEAAAAAAAAAEQAAAAAEAAAEAAAQAAAAAAAAAAAAAA=</HashCode>
</TypeIdentifier>
</Interface>
<Interface Name="Aga.Controls.Tree.IToolTipProvider">
<Position X="4.5" Y="0.5" Width="2.75" />
<TypeIdentifier>
<FileName>Tree\IToolTipProvider.cs</FileName>
<HashCode>AAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
</TypeIdentifier>
</Interface>
</ClassDiagram>

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
namespace Aga.Controls.Tree
{
/*internal class ColumnCollection: Collection<Column>
{
public int TotalWidth
{
get
{
int res = 0;
foreach (Column c in Items)
res += c.Width;
return res;
}
}
}*/
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public struct DrawContext
{
private Graphics _graphics;
public Graphics Graphics
{
get { return _graphics; }
set { _graphics = value; }
}
private Rectangle _bounds;
public Rectangle Bounds
{
get { return _bounds; }
set { _bounds = value; }
}
private Font _font;
public Font Font
{
get { return _font; }
set { _font = value; }
}
private DrawSelectionMode _drawSelection;
public DrawSelectionMode DrawSelection
{
get { return _drawSelection; }
set { _drawSelection = value; }
}
private bool _drawFocus;
public bool DrawFocus
{
get { return _drawFocus; }
set { _drawFocus = value; }
}
private NodeControl _currentEditorOwner;
public NodeControl CurrentEditorOwner
{
get { return _currentEditorOwner; }
set { _currentEditorOwner = value; }
}
private bool _enabled;
public bool Enabled
{
get { return _enabled; }
set { _enabled = value; }
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Drawing;
namespace Aga.Controls.Tree
{
public class DropNodeValidatingEventArgs: EventArgs
{
Point _point;
TreeNodeAdv _node;
public DropNodeValidatingEventArgs(Point point, TreeNodeAdv node)
{
_point = point;
_node = node;
}
public Point Point
{
get { return _point; }
}
public TreeNodeAdv Node
{
get { return _node; }
set { _node = value; }
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public struct DropPosition
{
private TreeNodeAdv _node;
public TreeNodeAdv Node
{
get { return _node; }
set { _node = value; }
}
private NodePosition _position;
public NodePosition Position
{
get { return _position; }
set { _position = value; }
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public struct EditorContext
{
private TreeNodeAdv _currentNode;
public TreeNodeAdv CurrentNode
{
get { return _currentNode; }
set { _currentNode = value; }
}
private Control _editor;
public Control Editor
{
get { return _editor; }
set { _editor = value; }
}
private NodeControl _owner;
public NodeControl Owner
{
get { return _owner; }
set { _owner = value; }
}
private Rectangle _bounds;
public Rectangle Bounds
{
get { return _bounds; }
set { _bounds = value; }
}
private DrawContext _drawContext;
public DrawContext DrawContext
{
get { return _drawContext; }
set { _drawContext = value; }
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public enum DrawSelectionMode
{
None, Active, Inactive, FullRowSelect
}
public enum TreeSelectionMode
{
Single, Multi, MultiSameParent
}
public enum NodePosition
{
Inside, Before, After
}
public enum VerticalAlignment
{
Top, Bottom, Center
}
public enum IncrementalSearchMode
{
None, Standard, Continuous
}
[Flags]
public enum GridLineStyle
{
None = 0,
Horizontal = 1,
Vertical = 2,
HorizontalAndVertical = 3
}
public enum ImageScaleMode
{
/// <summary>
/// Don't scale
/// </summary>
Clip,
/// <summary>
/// Scales image to fit the display rectangle, aspect ratio is not fixed.
/// </summary>
Fit,
/// <summary>
/// Scales image down if it is larger than display rectangle, taking aspect ratio into account
/// </summary>
ScaleDown,
/// <summary>
/// Scales image up if it is smaller than display rectangle, taking aspect ratio into account
/// </summary>
ScaleUp,
/// <summary>
/// Scales image to match the display rectangle, taking aspect ratio into account
/// </summary>
AlwaysScale,
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace Aga.Controls.Tree
{
internal class FixedRowHeightLayout : IRowLayout
{
private TreeViewAdv _treeView;
public FixedRowHeightLayout(TreeViewAdv treeView, int rowHeight)
{
_treeView = treeView;
PreferredRowHeight = rowHeight;
}
private int _rowHeight;
public int PreferredRowHeight
{
get { return _rowHeight; }
set { _rowHeight = value; }
}
public Rectangle GetRowBounds(int rowNo)
{
return new Rectangle(0, rowNo * _rowHeight, 0, _rowHeight);
}
public int PageRowCount
{
get
{
return Math.Max((_treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight) / _rowHeight, 0);
}
}
public int CurrentPageSize
{
get
{
return PageRowCount;
}
}
public int GetRowAt(Point point)
{
point = new Point(point.X, point.Y + (_treeView.FirstVisibleRow * _rowHeight) - _treeView.ColumnHeaderHeight);
return point.Y / _rowHeight;
}
public int GetFirstRow(int lastPageRow)
{
return Math.Max(0, lastPageRow - PageRowCount + 1);
}
public void ClearCache()
{
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace Aga.Controls.Tree
{
internal interface IRowLayout
{
int PreferredRowHeight
{
get;
set;
}
int PageRowCount
{
get;
}
int CurrentPageSize
{
get;
}
Rectangle GetRowBounds(int rowNo);
int GetRowAt(Point point);
int GetFirstRow(int lastPageRow);
void ClearCache();
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public interface IToolTipProvider
{
string GetToolTip(TreeNodeAdv node, NodeControl nodeControl);
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace Aga.Controls.Tree
{
public interface ITreeModel
{
IEnumerable GetChildren(TreePath treePath);
bool IsLeaf(TreePath treePath);
event EventHandler<TreeModelEventArgs> NodesChanged;
event EventHandler<TreeModelEventArgs> NodesInserted;
event EventHandler<TreeModelEventArgs> NodesRemoved;
event EventHandler<TreePathEventArgs> StructureChanged;
}
}

View File

@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Text;
using Aga.Controls.Tree.NodeControls;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Aga.Controls.Tree
{
internal class IncrementalSearch
{
private const int SearchTimeout = 300; //end of incremental search timeot in msec
private TreeViewAdv _tree;
private TreeNodeAdv _currentNode;
private string _searchString = "";
private DateTime _lastKeyPressed = DateTime.Now;
public IncrementalSearch(TreeViewAdv tree)
{
_tree = tree;
}
public void Search(Char value)
{
if (!Char.IsControl(value))
{
Char ch = Char.ToLowerInvariant(value);
DateTime dt = DateTime.Now;
TimeSpan ts = dt - _lastKeyPressed;
_lastKeyPressed = dt;
if (ts.TotalMilliseconds < SearchTimeout)
{
if (_searchString == value.ToString())
FirstCharSearch(ch);
else
ContinuousSearch(ch);
}
else
{
FirstCharSearch(ch);
}
}
}
private void ContinuousSearch(Char value)
{
if (value == ' ' && String.IsNullOrEmpty(_searchString))
return; //Ingnore leading space
_searchString += value;
DoContinuousSearch();
}
private void FirstCharSearch(Char value)
{
if (value == ' ')
return;
_searchString = value.ToString();
TreeNodeAdv node = null;
if (_tree.SelectedNode != null)
node = _tree.SelectedNode.NextVisibleNode;
if (node == null)
node = _tree.Root.NextVisibleNode;
if (node != null)
foreach (string label in IterateNodeLabels(node))
{
if (label.StartsWith(_searchString))
{
_tree.SelectedNode = _currentNode;
return;
}
}
}
public virtual void EndSearch()
{
_currentNode = null;
_searchString = "";
}
protected IEnumerable<string> IterateNodeLabels(TreeNodeAdv start)
{
_currentNode = start;
while(_currentNode != null)
{
foreach (string label in GetNodeLabels(_currentNode))
yield return label;
_currentNode = _currentNode.NextVisibleNode;
if (_currentNode == null)
_currentNode = _tree.Root;
if (start == _currentNode)
break;
}
}
private IEnumerable<string> GetNodeLabels(TreeNodeAdv node)
{
foreach (NodeControl nc in _tree.NodeControls)
{
BindableControl bc = nc as BindableControl;
if (bc != null && bc.IncrementalSearchEnabled)
{
object obj = bc.GetValue(node);
if (obj != null)
yield return obj.ToString().ToLowerInvariant();
}
}
}
private bool DoContinuousSearch()
{
bool found = false;
if (!String.IsNullOrEmpty(_searchString))
{
TreeNodeAdv node = null;
if (_tree.SelectedNode != null)
node = _tree.SelectedNode;
if (node == null)
node = _tree.Root.NextVisibleNode;
if (!String.IsNullOrEmpty(_searchString))
{
foreach (string label in IterateNodeLabels(node))
{
if (label.StartsWith(_searchString))
{
found = true;
_tree.SelectedNode = _currentNode;
break;
}
}
}
}
return found;
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace Aga.Controls.Tree
{
internal class ClickColumnState : ColumnState
{
private Point _location;
public ClickColumnState(TreeViewAdv tree, TreeColumn column, Point location)
: base(tree, column)
{
_location = location;
}
public override void KeyDown(KeyEventArgs args)
{
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
}
public override bool MouseMove(MouseEventArgs args)
{
if (TreeViewAdv.Dist(_location, args.Location) > TreeViewAdv.ItemDragSensivity
&& Tree.AllowColumnReorder)
{
Tree.Input = new ReorderColumnState(Tree, Column, args.Location);
Tree.UpdateView();
}
return true;
}
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
{
Tree.ChangeInput();
Tree.UpdateView();
Tree.OnColumnClicked(Column);
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
internal abstract class ColumnState : InputState
{
private TreeColumn _column;
public TreeColumn Column
{
get { return _column; }
}
public ColumnState(TreeViewAdv tree, TreeColumn column)
: base(tree)
{
_column = column;
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Windows.Forms;
namespace Aga.Controls.Tree
{
internal abstract class InputState
{
private TreeViewAdv _tree;
public TreeViewAdv Tree
{
get { return _tree; }
}
public InputState(TreeViewAdv tree)
{
_tree = tree;
}
public abstract void KeyDown(System.Windows.Forms.KeyEventArgs args);
public abstract void MouseDown(TreeNodeAdvMouseEventArgs args);
public abstract void MouseUp(TreeNodeAdvMouseEventArgs args);
/// <summary>
/// handle OnMouseMove event
/// </summary>
/// <param name="args"></param>
/// <returns>true if event was handled and should be dispatched</returns>
public virtual bool MouseMove(MouseEventArgs args)
{
return false;
}
public virtual void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
{
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
internal class InputWithControl: NormalInputState
{
public InputWithControl(TreeViewAdv tree): base(tree)
{
}
protected override void DoMouseOperation(TreeNodeAdvMouseEventArgs args)
{
if (Tree.SelectionMode == TreeSelectionMode.Single)
{
base.DoMouseOperation(args);
}
else if (CanSelect(args.Node))
{
args.Node.IsSelected = !args.Node.IsSelected;
Tree.SelectionStart = args.Node;
}
}
protected override void MouseDownAtEmptySpace(TreeNodeAdvMouseEventArgs args)
{
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
internal class InputWithShift: NormalInputState
{
public InputWithShift(TreeViewAdv tree): base(tree)
{
}
protected override void FocusRow(TreeNodeAdv node)
{
Tree.SuspendSelectionEvent = true;
try
{
if (Tree.SelectionMode == TreeSelectionMode.Single || Tree.SelectionStart == null)
base.FocusRow(node);
else if (CanSelect(node))
{
SelectAllFromStart(node);
Tree.CurrentNode = node;
Tree.ScrollTo(node);
}
}
finally
{
Tree.SuspendSelectionEvent = false;
}
}
protected override void DoMouseOperation(TreeNodeAdvMouseEventArgs args)
{
if (Tree.SelectionMode == TreeSelectionMode.Single || Tree.SelectionStart == null)
{
base.DoMouseOperation(args);
}
else if (CanSelect(args.Node))
{
Tree.SuspendSelectionEvent = true;
try
{
SelectAllFromStart(args.Node);
}
finally
{
Tree.SuspendSelectionEvent = false;
}
}
}
protected override void MouseDownAtEmptySpace(TreeNodeAdvMouseEventArgs args)
{
}
private void SelectAllFromStart(TreeNodeAdv node)
{
Tree.ClearSelectionInternal();
int a = node.Row;
int b = Tree.SelectionStart.Row;
for (int i = Math.Min(a, b); i <= Math.Max(a, b); i++)
{
if (Tree.SelectionMode == TreeSelectionMode.Multi || Tree.RowMap[i].Parent == node.Parent)
Tree.RowMap[i].IsSelected = true;
}
}
}
}

View File

@@ -0,0 +1,202 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace Aga.Controls.Tree
{
internal class NormalInputState : InputState
{
private bool _mouseDownFlag = false;
public NormalInputState(TreeViewAdv tree) : base(tree)
{
}
public override void KeyDown(KeyEventArgs args)
{
if (Tree.CurrentNode == null && Tree.Root.Nodes.Count > 0)
Tree.CurrentNode = Tree.Root.Nodes[0];
if (Tree.CurrentNode != null)
{
switch (args.KeyCode)
{
case Keys.Right:
if (!Tree.CurrentNode.IsExpanded)
Tree.CurrentNode.IsExpanded = true;
else if (Tree.CurrentNode.Nodes.Count > 0)
Tree.SelectedNode = Tree.CurrentNode.Nodes[0];
args.Handled = true;
break;
case Keys.Left:
if (Tree.CurrentNode.IsExpanded)
Tree.CurrentNode.IsExpanded = false;
else if (Tree.CurrentNode.Parent != Tree.Root)
Tree.SelectedNode = Tree.CurrentNode.Parent;
args.Handled = true;
break;
case Keys.Down:
NavigateForward(1);
args.Handled = true;
break;
case Keys.Up:
NavigateBackward(1);
args.Handled = true;
break;
case Keys.PageDown:
NavigateForward(Math.Max(1, Tree.CurrentPageSize - 1));
args.Handled = true;
break;
case Keys.PageUp:
NavigateBackward(Math.Max(1, Tree.CurrentPageSize - 1));
args.Handled = true;
break;
case Keys.Home:
if (Tree.RowMap.Count > 0)
FocusRow(Tree.RowMap[0]);
args.Handled = true;
break;
case Keys.End:
if (Tree.RowMap.Count > 0)
FocusRow(Tree.RowMap[Tree.RowMap.Count-1]);
args.Handled = true;
break;
case Keys.Subtract:
Tree.CurrentNode.Collapse();
args.Handled = true;
args.SuppressKeyPress = true;
break;
case Keys.Add:
Tree.CurrentNode.Expand();
args.Handled = true;
args.SuppressKeyPress = true;
break;
case Keys.Multiply:
Tree.CurrentNode.ExpandAll();
args.Handled = true;
args.SuppressKeyPress = true;
break;
case Keys.A:
if (args.Modifiers == Keys.Control)
Tree.SelectAllNodes();
break;
}
}
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
if (args.Node != null)
{
Tree.ItemDragMode = true;
Tree.ItemDragStart = args.Location;
if (args.Button == MouseButtons.Left || args.Button == MouseButtons.Right)
{
Tree.BeginUpdate();
try
{
Tree.CurrentNode = args.Node;
if (args.Node.IsSelected)
_mouseDownFlag = true;
else
{
_mouseDownFlag = false;
DoMouseOperation(args);
}
}
finally
{
Tree.EndUpdate();
}
}
}
else
{
Tree.ItemDragMode = false;
MouseDownAtEmptySpace(args);
}
}
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
{
Tree.ItemDragMode = false;
if (_mouseDownFlag && args.Node != null)
{
if (args.Button == MouseButtons.Left)
DoMouseOperation(args);
else if (args.Button == MouseButtons.Right)
Tree.CurrentNode = args.Node;
}
_mouseDownFlag = false;
}
private void NavigateBackward(int n)
{
int row = Math.Max(Tree.CurrentNode.Row - n, 0);
if (row != Tree.CurrentNode.Row)
FocusRow(Tree.RowMap[row]);
}
private void NavigateForward(int n)
{
int row = Math.Min(Tree.CurrentNode.Row + n, Tree.RowCount - 1);
if (row != Tree.CurrentNode.Row)
FocusRow(Tree.RowMap[row]);
}
protected virtual void MouseDownAtEmptySpace(TreeNodeAdvMouseEventArgs args)
{
Tree.ClearSelection();
}
protected virtual void FocusRow(TreeNodeAdv node)
{
Tree.SuspendSelectionEvent = true;
try
{
Tree.ClearSelectionInternal();
Tree.CurrentNode = node;
Tree.SelectionStart = node;
node.IsSelected = true;
Tree.ScrollTo(node);
}
finally
{
Tree.SuspendSelectionEvent = false;
}
}
protected bool CanSelect(TreeNodeAdv node)
{
if (Tree.SelectionMode == TreeSelectionMode.MultiSameParent)
{
return (Tree.SelectionStart == null || node.Parent == Tree.SelectionStart.Parent);
}
else
return true;
}
protected virtual void DoMouseOperation(TreeNodeAdvMouseEventArgs args)
{
if (Tree.SelectedNodes.Count == 1 && args.Node != null && args.Node.IsSelected)
return;
Tree.SuspendSelectionEvent = true;
try
{
Tree.ClearSelectionInternal();
if (args.Node != null)
args.Node.IsSelected = true;
Tree.SelectionStart = args.Node;
}
finally
{
Tree.SuspendSelectionEvent = false;
}
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace Aga.Controls.Tree
{
internal class ReorderColumnState : ColumnState
{
#region Properties
private Point _location;
public Point Location
{
get { return _location; }
}
private Bitmap _ghostImage;
public Bitmap GhostImage
{
get { return _ghostImage; }
}
private TreeColumn _dropColumn;
public TreeColumn DropColumn
{
get { return _dropColumn; }
}
private int _dragOffset;
public int DragOffset
{
get { return _dragOffset; }
}
#endregion
public ReorderColumnState(TreeViewAdv tree, TreeColumn column, Point initialMouseLocation)
: base(tree, column)
{
_location = new Point(initialMouseLocation.X + Tree.OffsetX, 0);
_dragOffset = tree.GetColumnX(column) - initialMouseLocation.X;
_ghostImage = column.CreateGhostImage(new Rectangle(0, 0, column.Width, tree.ColumnHeaderHeight), tree.Font);
}
public override void KeyDown(KeyEventArgs args)
{
args.Handled = true;
if (args.KeyCode == Keys.Escape)
FinishResize();
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
}
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
{
FinishResize();
}
public override bool MouseMove(MouseEventArgs args)
{
_dropColumn = null;
_location = new Point(args.X + Tree.OffsetX, 0);
int x = 0;
foreach (TreeColumn c in Tree.Columns)
{
if (c.IsVisible)
{
if (_location.X < x + c.Width / 2)
{
_dropColumn = c;
break;
}
x += c.Width;
}
}
Tree.UpdateHeaders();
return true;
}
private void FinishResize()
{
Tree.ChangeInput();
if (Column == DropColumn)
Tree.UpdateView();
else
{
Tree.Columns.Remove(Column);
if (DropColumn == null)
Tree.Columns.Add(Column);
else
Tree.Columns.Insert(Tree.Columns.IndexOf(DropColumn), Column);
Tree.OnColumnReordered(Column);
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Security.Permissions;
using System.Drawing;
namespace Aga.Controls.Tree
{
internal class ResizeColumnState: ColumnState
{
private Point _initLocation;
private int _initWidth;
public ResizeColumnState(TreeViewAdv tree, TreeColumn column, Point p)
: base(tree, column)
{
_initLocation = p;
_initWidth = column.Width;
}
public override void KeyDown(KeyEventArgs args)
{
args.Handled = true;
if (args.KeyCode == Keys.Escape)
FinishResize();
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
}
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
{
FinishResize();
}
private void FinishResize()
{
Tree.ChangeInput();
Tree.FullUpdate();
Tree.OnColumnWidthChanged(Column);
}
public override bool MouseMove(MouseEventArgs args)
{
Column.Width = _initWidth + args.Location.X - _initLocation.X;
Tree.UpdateView();
return true;
}
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
{
Tree.AutoSizeColumn(Column);
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace Aga.Controls.Tree
{
public class ListModel : TreeModelBase
{
private IList _list;
public int Count
{
get { return _list.Count; }
}
public ListModel()
{
_list = new List<object>();
}
public ListModel(IList list)
{
_list = list;
}
public override IEnumerable GetChildren(TreePath treePath)
{
return _list;
}
public override bool IsLeaf(TreePath treePath)
{
return true;
}
public void AddRange(IEnumerable items)
{
foreach (object obj in items)
_list.Add(obj);
OnStructureChanged(new TreePathEventArgs(TreePath.Empty));
}
public void Add(object item)
{
_list.Add(item);
OnNodesInserted(new TreeModelEventArgs(TreePath.Empty, new int[] { _list.Count - 1 }, new object[] { item }));
}
public void Clear()
{
_list.Clear();
OnStructureChanged(new TreePathEventArgs(TreePath.Empty));
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Aga.Controls.Tree
{
internal static class NativeMethods
{
public const int DCX_WINDOW = 0x01;
public const int DCX_CACHE = 0x02;
public const int DCX_NORESETATTRS = 0x04;
public const int DCX_CLIPCHILDREN = 0x08;
public const int DCX_CLIPSIBLINGS = 0x10;
public const int DCX_PARENTCLIP = 0x20;
public const int DCX_EXCLUDERGN = 0x40;
public const int DCX_INTERSECTRGN = 0x80;
public const int DCX_EXCLUDEUPDATE = 0x100;
public const int DCX_INTERSECTUPDATE = 0x200;
public const int DCX_LOCKWINDOWUPDATE = 0x400;
public const int DCX_VALIDATE = 0x200000;
public const int WM_THEMECHANGED = 0x031A;
public const int WM_NCPAINT = 0x85;
public const int WM_NCCALCSIZE = 0x83;
public const int WS_BORDER = 0x800000;
public const int WS_EX_CLIENTEDGE = 0x200;
public const int WVR_HREDRAW = 0x100;
public const int WVR_VREDRAW = 0x200;
public const int WVR_REDRAW = (WVR_HREDRAW | WVR_VREDRAW);
[StructLayout(LayoutKind.Sequential)]
public struct NCCALCSIZE_PARAMS
{
public RECT rgrc0, rgrc1, rgrc2;
public IntPtr lppos;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public static RECT FromRectangle(Rectangle rectangle)
{
RECT result = new RECT();
result.Left = rectangle.Left;
result.Top = rectangle.Top;
result.Right = rectangle.Right;
result.Bottom = rectangle.Bottom;
return result;
}
public Rectangle ToRectangle()
{
return new Rectangle(Left, Top, Right - Left, Bottom - Top);
}
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetDCEx(IntPtr hWnd, IntPtr hrgnClip, int flags);
[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
}
}

View File

@@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using System.Drawing;
namespace Aga.Controls.Tree
{
public class Node
{
#region NodeCollection
private class NodeCollection : Collection<Node>
{
private Node _owner;
public NodeCollection(Node owner)
{
_owner = owner;
}
protected override void ClearItems()
{
while (this.Count != 0)
this.RemoveAt(this.Count - 1);
}
protected override void InsertItem(int index, Node item)
{
if (item == null)
throw new ArgumentNullException("item");
if (item.Parent != _owner)
{
if (item.Parent != null)
item.Parent.Nodes.Remove(item);
item._parent = _owner;
item._index = index;
for (int i = index; i < Count; i++)
this[i]._index++;
base.InsertItem(index, item);
TreeModel model = _owner.FindModel();
if (model != null)
model.OnNodeInserted(_owner, index, item);
}
}
protected override void RemoveItem(int index)
{
Node item = this[index];
item._parent = null;
item._index = -1;
for (int i = index + 1; i < Count; i++)
this[i]._index--;
base.RemoveItem(index);
TreeModel model = _owner.FindModel();
if (model != null)
model.OnNodeRemoved(_owner, index, item);
}
protected override void SetItem(int index, Node item)
{
if (item == null)
throw new ArgumentNullException("item");
RemoveAt(index);
InsertItem(index, item);
}
}
#endregion
#region Properties
private TreeModel _model;
internal TreeModel Model
{
get { return _model; }
set { _model = value; }
}
private NodeCollection _nodes;
public Collection<Node> Nodes
{
get { return _nodes; }
}
private Node _parent;
public Node Parent
{
get { return _parent; }
set
{
if (value != _parent)
{
if (_parent != null)
_parent.Nodes.Remove(this);
if (value != null)
value.Nodes.Add(this);
}
}
}
private int _index = -1;
public int Index
{
get
{
return _index;
}
}
public Node PreviousNode
{
get
{
int index = Index;
if (index > 0)
return _parent.Nodes[index - 1];
else
return null;
}
}
public Node NextNode
{
get
{
int index = Index;
if (index >= 0 && index < _parent.Nodes.Count - 1)
return _parent.Nodes[index + 1];
else
return null;
}
}
private string _text;
public virtual string Text
{
get { return _text; }
set
{
if (_text != value)
{
_text = value;
NotifyModel();
}
}
}
private CheckState _checkState;
public virtual CheckState CheckState
{
get { return _checkState; }
set
{
if (_checkState != value)
{
_checkState = value;
NotifyModel();
}
}
}
private Image _image;
public Image Image
{
get { return _image; }
set
{
if (_image != value)
{
_image = value;
NotifyModel();
}
}
}
private object _tag;
public object Tag
{
get { return _tag; }
set { _tag = value; }
}
public bool IsChecked
{
get
{
return CheckState != CheckState.Unchecked;
}
set
{
if (value)
CheckState = CheckState.Checked;
else
CheckState = CheckState.Unchecked;
}
}
public virtual bool IsLeaf
{
get
{
return false;
}
}
#endregion
public Node()
: this(string.Empty)
{
}
public Node(string text)
{
_text = text;
_nodes = new NodeCollection(this);
}
public override string ToString()
{
return Text;
}
private TreeModel FindModel()
{
Node node = this;
while (node != null)
{
if (node.Model != null)
return node.Model;
node = node.Parent;
}
return null;
}
protected void NotifyModel()
{
TreeModel model = FindModel();
if (model != null && Parent != null)
{
TreePath path = model.GetPath(Parent);
if (path != null)
{
TreeModelEventArgs args = new TreeModelEventArgs(path, new int[] { Index }, new object[] { this });
model.OnNodesChanged(args);
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text;
using Aga.Controls.Tree.NodeControls;
using System.Drawing;
namespace Aga.Controls.Tree
{
public struct NodeControlInfo
{
public static readonly NodeControlInfo Empty = new NodeControlInfo(null, Rectangle.Empty, null);
private NodeControl _control;
public NodeControl Control
{
get { return _control; }
}
private Rectangle _bounds;
public Rectangle Bounds
{
get { return _bounds; }
}
private TreeNodeAdv _node;
public TreeNodeAdv Node
{
get { return _node; }
}
public NodeControlInfo(NodeControl control, Rectangle bounds, TreeNodeAdv node)
{
_control = control;
_bounds = bounds;
_node = node;
}
}
}

View File

@@ -0,0 +1,314 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public abstract class BaseTextControl : EditableControl
{
private TextFormatFlags _baseFormatFlags;
private TextFormatFlags _formatFlags;
private Pen _focusPen;
private StringFormat _format;
#region Properties
private Font _font = null;
public Font Font
{
get
{
if (_font == null)
return Control.DefaultFont;
else
return _font;
}
set
{
if (value == Control.DefaultFont)
_font = null;
else
_font = value;
}
}
protected bool ShouldSerializeFont()
{
return (_font != null);
}
private HorizontalAlignment _textAlign = HorizontalAlignment.Left;
[DefaultValue(HorizontalAlignment.Left)]
public HorizontalAlignment TextAlign
{
get { return _textAlign; }
set
{
_textAlign = value;
SetFormatFlags();
}
}
private StringTrimming _trimming = StringTrimming.None;
[DefaultValue(StringTrimming.None)]
public StringTrimming Trimming
{
get { return _trimming; }
set
{
_trimming = value;
SetFormatFlags();
}
}
private bool _displayHiddenContentInToolTip = true;
[DefaultValue(true)]
public bool DisplayHiddenContentInToolTip
{
get { return _displayHiddenContentInToolTip; }
set { _displayHiddenContentInToolTip = value; }
}
private bool _useCompatibleTextRendering = false;
[DefaultValue(false)]
public bool UseCompatibleTextRendering
{
get { return _useCompatibleTextRendering; }
set { _useCompatibleTextRendering = value; }
}
[DefaultValue(false)]
public bool TrimMultiLine
{
get;
set;
}
#endregion
protected BaseTextControl()
{
IncrementalSearchEnabled = true;
_focusPen = new Pen(Color.Black);
_focusPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
_format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox | StringFormatFlags.MeasureTrailingSpaces);
_baseFormatFlags = TextFormatFlags.PreserveGraphicsClipping |
TextFormatFlags.PreserveGraphicsTranslateTransform;
SetFormatFlags();
LeftMargin = 3;
}
private void SetFormatFlags()
{
_format.Alignment = TextHelper.TranslateAligment(TextAlign);
_format.Trimming = Trimming;
_formatFlags = _baseFormatFlags | TextHelper.TranslateAligmentToFlag(TextAlign)
| TextHelper.TranslateTrimmingToFlag(Trimming);
}
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{
return GetLabelSize(node, context);
}
protected Size GetLabelSize(TreeNodeAdv node, DrawContext context)
{
return GetLabelSize(node, context, GetLabel(node));
}
protected Size GetLabelSize(TreeNodeAdv node, DrawContext context, string label)
{
PerformanceAnalyzer.Start("GetLabelSize");
CheckThread();
Font font = GetDrawingFont(node, context, label);
Size s = Size.Empty;
if (UseCompatibleTextRendering)
s = TextRenderer.MeasureText(label, font);
else
{
SizeF sf = context.Graphics.MeasureString(label, font);
s = new Size((int)Math.Ceiling(sf.Width), (int)Math.Ceiling(sf.Height));
}
PerformanceAnalyzer.Finish("GetLabelSize");
if (!s.IsEmpty)
return s;
else
return new Size(10, Font.Height);
}
protected Font GetDrawingFont(TreeNodeAdv node, DrawContext context, string label)
{
Font font = context.Font;
if (DrawTextMustBeFired(node))
{
DrawEventArgs args = new DrawEventArgs(node, this, context, label);
args.Font = context.Font;
OnDrawText(args);
font = args.Font;
}
return font;
}
protected void SetEditControlProperties(Control control, TreeNodeAdv node)
{
string label = GetLabel(node);
DrawContext context = new DrawContext();
context.Font = control.Font;
control.Font = GetDrawingFont(node, context, label);
}
public override void Draw(TreeNodeAdv node, DrawContext context)
{
if (context.CurrentEditorOwner == this && node == Parent.CurrentNode)
return;
PerformanceAnalyzer.Start("BaseTextControl.Draw");
string label = GetLabel(node);
Rectangle bounds = GetBounds(node, context);
Rectangle focusRect = new Rectangle(bounds.X, context.Bounds.Y,
bounds.Width, context.Bounds.Height);
Brush backgroundBrush;
Color textColor;
Font font;
CreateBrushes(node, context, label, out backgroundBrush, out textColor, out font, ref label);
if (backgroundBrush != null)
context.Graphics.FillRectangle(backgroundBrush, focusRect);
if (context.DrawFocus)
{
focusRect.Width--;
focusRect.Height--;
if (context.DrawSelection == DrawSelectionMode.None)
_focusPen.Color = SystemColors.ControlText;
else
_focusPen.Color = SystemColors.InactiveCaption;
context.Graphics.DrawRectangle(_focusPen, focusRect);
}
PerformanceAnalyzer.Start("BaseTextControl.DrawText");
if (UseCompatibleTextRendering)
TextRenderer.DrawText(context.Graphics, label, font, bounds, textColor, _formatFlags);
else
context.Graphics.DrawString(label, font, GetFrush(textColor), bounds, _format);
PerformanceAnalyzer.Finish("BaseTextControl.DrawText");
PerformanceAnalyzer.Finish("BaseTextControl.Draw");
}
private static Dictionary<Color, Brush> _brushes = new Dictionary<Color,Brush>();
private static Brush GetFrush(Color color)
{
Brush br;
if (_brushes.ContainsKey(color))
br = _brushes[color];
else
{
br = new SolidBrush(color);
_brushes.Add(color, br);
}
return br;
}
private void CreateBrushes(TreeNodeAdv node, DrawContext context, string text, out Brush backgroundBrush, out Color textColor, out Font font, ref string label)
{
textColor = Parent.ForeColor;
backgroundBrush = null;
font = context.Font;
if (context.DrawSelection == DrawSelectionMode.Active)
{
textColor = SystemColors.HighlightText;
backgroundBrush = SystemBrushes.Highlight;
}
else if (context.DrawSelection == DrawSelectionMode.Inactive)
{
textColor = Parent.ForeColor;
backgroundBrush = SystemBrushes.InactiveBorder;
}
else if (context.DrawSelection == DrawSelectionMode.FullRowSelect)
textColor = Parent.ForeColor;
if (!context.Enabled)
textColor = SystemColors.GrayText;
if (DrawTextMustBeFired(node))
{
DrawEventArgs args = new DrawEventArgs(node, this, context, text);
args.Text = label;
args.TextColor = textColor;
args.BackgroundBrush = backgroundBrush;
args.Font = font;
OnDrawText(args);
textColor = args.TextColor;
backgroundBrush = args.BackgroundBrush;
font = args.Font;
label = args.Text;
}
}
public string GetLabel(TreeNodeAdv node)
{
if (node != null && node.Tag != null)
{
object obj = GetValue(node);
if (obj != null)
return FormatLabel(obj);
}
return string.Empty;
}
protected virtual string FormatLabel(object obj)
{
var res = obj.ToString();
if (TrimMultiLine && res != null)
{
string[] parts = res.Split('\n');
if (parts.Length > 1)
return parts[0] + "...";
}
return res;
}
public void SetLabel(TreeNodeAdv node, string value)
{
SetValue(node, value);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_focusPen.Dispose();
_format.Dispose();
}
}
/// <summary>
/// Fires when control is going to draw a text. Can be used to change text or back color
/// </summary>
public event EventHandler<DrawEventArgs> DrawText;
protected virtual void OnDrawText(DrawEventArgs args)
{
TreeViewAdv tree = args.Node.Tree;
if (tree != null)
tree.FireDrawControl(args);
if (DrawText != null)
DrawText(this, args);
}
protected virtual bool DrawTextMustBeFired(TreeNodeAdv node)
{
return DrawText != null || (node.Tree != null && node.Tree.DrawControlMustBeFired());
}
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public abstract class BindableControl : NodeControl
{
private struct MemberAdapter
{
private object _obj;
private PropertyInfo _pi;
private FieldInfo _fi;
public static readonly MemberAdapter Empty = new MemberAdapter();
public Type MemberType
{
get
{
if (_pi != null)
return _pi.PropertyType;
else if (_fi != null)
return _fi.FieldType;
else
return null;
}
}
public object Value
{
get
{
if (_pi != null && _pi.CanRead)
return _pi.GetValue(_obj, null);
else if (_fi != null)
return _fi.GetValue(_obj);
else
return null;
}
set
{
if (_pi != null && _pi.CanWrite)
_pi.SetValue(_obj, value, null);
else if (_fi != null)
_fi.SetValue(_obj, value);
}
}
public MemberAdapter(object obj, PropertyInfo pi)
{
_obj = obj;
_pi = pi;
_fi = null;
}
public MemberAdapter(object obj, FieldInfo fi)
{
_obj = obj;
_fi = fi;
_pi = null;
}
}
#region Properties
private bool _virtualMode = false;
[DefaultValue(false), Category("Data")]
public bool VirtualMode
{
get { return _virtualMode; }
set { _virtualMode = value; }
}
private string _propertyName = "";
[DefaultValue(""), Category("Data")]
public string DataPropertyName
{
get { return _propertyName; }
set
{
if (_propertyName == null)
_propertyName = string.Empty;
_propertyName = value;
}
}
private bool _incrementalSearchEnabled = false;
[DefaultValue(false)]
public bool IncrementalSearchEnabled
{
get { return _incrementalSearchEnabled; }
set { _incrementalSearchEnabled = value; }
}
#endregion
public virtual object GetValue(TreeNodeAdv node)
{
if (VirtualMode)
{
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
OnValueNeeded(args);
return args.Value;
}
else
{
try
{
return GetMemberAdapter(node).Value;
}
catch (TargetInvocationException ex)
{
if (ex.InnerException != null)
throw new ArgumentException(ex.InnerException.Message, ex.InnerException);
else
throw new ArgumentException(ex.Message);
}
}
}
public virtual void SetValue(TreeNodeAdv node, object value)
{
if (VirtualMode)
{
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
args.Value = value;
OnValuePushed(args);
}
else
{
try
{
MemberAdapter ma = GetMemberAdapter(node);
ma.Value = value;
}
catch (TargetInvocationException ex)
{
if (ex.InnerException != null)
throw new ArgumentException(ex.InnerException.Message, ex.InnerException);
else
throw new ArgumentException(ex.Message);
}
}
}
public Type GetPropertyType(TreeNodeAdv node)
{
return GetMemberAdapter(node).MemberType;
}
private MemberAdapter GetMemberAdapter(TreeNodeAdv node)
{
if (node.Tag != null && !string.IsNullOrEmpty(DataPropertyName))
{
Type type = node.Tag.GetType();
PropertyInfo pi = type.GetProperty(DataPropertyName);
if (pi != null)
return new MemberAdapter(node.Tag, pi);
else
{
FieldInfo fi = type.GetField(DataPropertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (fi != null)
return new MemberAdapter(node.Tag, fi);
}
}
return MemberAdapter.Empty;
}
public override string ToString()
{
if (string.IsNullOrEmpty(DataPropertyName))
return GetType().Name;
else
return string.Format("{0} ({1})", GetType().Name, DataPropertyName);
}
public event EventHandler<NodeControlValueEventArgs> ValueNeeded;
private void OnValueNeeded(NodeControlValueEventArgs args)
{
if (ValueNeeded != null)
ValueNeeded(this, args);
}
public event EventHandler<NodeControlValueEventArgs> ValuePushed;
private void OnValuePushed(NodeControlValueEventArgs args)
{
if (ValuePushed != null)
ValuePushed(this, args);
}
}
}

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Font Name="Microsoft Sans Serif" Size="8.25" />
<Class Name="Aga.Controls.Tree.NodeControls.NodeStateIcon" Collapsed="true">
<Position X="0.5" Y="4" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeStateIcon.cs</FileName>
<HashCode>ABAAAAAAAAQAQAAAAAAAAAAAAAAAAAAAQIAAAAAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.BindableControl" Collapsed="true">
<Position X="2.75" Y="1.5" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\BindableControl.cs</FileName>
<HashCode>FAAAAAAQIBAQCgAEAAAAIAAAAAAAAAEMAAACAAAAAAE=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeCheckBox" Collapsed="true">
<Position X="5" Y="4" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeCheckBox.cs</FileName>
<HashCode>AAEAAAAAAAACgkQCAAAAAAigAgAAEGABAAAIAAAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeControl" Collapsed="true">
<Position X="1.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeControl.cs</FileName>
<HashCode>AAAAAJAAgIgBkkoQAAgAQAAwAAABEIQAAEBIAAAAAAA=</HashCode>
</TypeIdentifier>
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
</Compartments>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeIcon" Collapsed="true">
<Position X="0.5" Y="2.75" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeIcon.cs</FileName>
<HashCode>ABAAAAAAAAAAAgAAAAAAAAAgAAAAAAAAAAAAAAAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodePlusMinus" Collapsed="true">
<Position X="0.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodePlusMinus.cs</FileName>
<HashCode>AAAAAAAAAAAAAgAAAAAAAEAgAAAAMCAAAAAIACAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.BaseTextControl" Collapsed="true">
<Position X="3" Y="5" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\BaseTextControl.cs</FileName>
<HashCode>AAAAICBQACAAIgACBCAEAQA8AgmFoAAwAAAAACACAMA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeTextBox" Collapsed="true">
<Position X="1" Y="6" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeTextBox.cs</FileName>
<HashCode>QQQAhAAAADAMgAAAABAAAAAAAgEAIAAAAAAAAIAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.EditableControl" Collapsed="true">
<Position X="3" Y="4" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\EditableControl.cs</FileName>
<HashCode>QQAgAAAACGgkAMAABAEEkADAEAAUEAAABAGoAAAAAQA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeComboBox" Collapsed="true">
<Position X="3" Y="6" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeComboBox.cs</FileName>
<HashCode>wQACAAAAAAAMAEBAAAAAAABAAAAAAAABAAAAAAAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeNumericUpDown" Collapsed="true">
<Position X="5" Y="6" Width="1.75" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeNumericUpDown.cs</FileName>
<HashCode>wQAAAACAAAAEAABAIAAQIAAAAAAAAAABAAAIAAAAAII=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.InteractiveControl" Collapsed="true">
<Position X="4" Y="2.75" Width="1.5" />
<TypeIdentifier>
<FileName>Tree\NodeControls\InteractiveControl.cs</FileName>
<HashCode>AAAABAAAAAAAAAAACAAAAAAAABAAAQAAAAAAAAIAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeDecimalTextBox" Collapsed="true">
<Position X="2.5" Y="7" Width="1.75" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeDecimalTextBox.cs</FileName>
<HashCode>AQAAAAAAAACAAAACAAAAAAQAAAAAIAAAAAgAAAAAAAA=</HashCode>
</TypeIdentifier>
</Class>
<Class Name="Aga.Controls.Tree.NodeControls.NodeIntegerTextBox" Collapsed="true">
<Position X="0.5" Y="7" Width="1.75" />
<TypeIdentifier>
<FileName>Tree\NodeControls\NodeIntegerTextBox.cs</FileName>
<HashCode>AQAAAAAAAAAAAAACAAAAAAQAAAAAIAAAAAAAAAAAAAA=</HashCode>
</TypeIdentifier>
</Class>
</ClassDiagram>

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace Aga.Controls.Tree.NodeControls
{
public class DrawEventArgs : NodeEventArgs
{
private DrawContext _context;
public DrawContext Context
{
get { return _context; }
}
private Brush _textBrush;
[Obsolete("Use TextColor")]
public Brush TextBrush
{
get { return _textBrush; }
set { _textBrush = value; }
}
private Brush _backgroundBrush;
public Brush BackgroundBrush
{
get { return _backgroundBrush; }
set { _backgroundBrush = value; }
}
private Font _font;
public Font Font
{
get { return _font; }
set { _font = value; }
}
private Color _textColor;
public Color TextColor
{
get { return _textColor; }
set { _textColor = value; }
}
private string _text;
public string Text
{
get { return _text; }
set { _text = value; }
}
private EditableControl _control;
public EditableControl Control
{
get { return _control; }
}
public DrawEventArgs(TreeNodeAdv node, EditableControl control, DrawContext context, string text)
: base(node)
{
_control = control;
_context = context;
_text = text;
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace Aga.Controls.Tree.NodeControls
{
public class EditEventArgs : NodeEventArgs
{
private Control _control;
public Control Control
{
get { return _control; }
}
public EditEventArgs(TreeNodeAdv node, Control control)
: base(node)
{
_control = control;
}
}
}

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public abstract class EditableControl : InteractiveControl
{
private Timer _timer;
private bool _editFlag;
#region Properties
private bool _editOnClick = false;
[DefaultValue(false)]
public bool EditOnClick
{
get { return _editOnClick; }
set { _editOnClick = value; }
}
#endregion
protected EditableControl()
{
_timer = new Timer();
_timer.Interval = 500;
_timer.Tick += new EventHandler(TimerTick);
}
private void TimerTick(object sender, EventArgs e)
{
_timer.Stop();
if (_editFlag)
BeginEdit();
_editFlag = false;
}
public void SetEditorBounds(EditorContext context)
{
Size size = CalculateEditorSize(context);
context.Editor.Bounds = new Rectangle(context.Bounds.X, context.Bounds.Y,
Math.Min(size.Width, context.Bounds.Width),
Math.Min(size.Height, Parent.ClientSize.Height - context.Bounds.Y)
);
}
protected abstract Size CalculateEditorSize(EditorContext context);
protected virtual bool CanEdit(TreeNodeAdv node)
{
return (node.Tag != null) && IsEditEnabled(node);
}
public void BeginEdit()
{
if (Parent != null && Parent.CurrentNode != null && CanEdit(Parent.CurrentNode))
{
CancelEventArgs args = new CancelEventArgs();
OnEditorShowing(args);
if (!args.Cancel)
{
var editor = CreateEditor(Parent.CurrentNode);
Parent.DisplayEditor(editor, this);
}
}
}
public void EndEdit(bool applyChanges)
{
if (Parent != null)
if (Parent.HideEditor(applyChanges))
OnEditorHided();
}
public virtual void UpdateEditor(Control control)
{
}
internal void ApplyChanges(TreeNodeAdv node, Control editor)
{
DoApplyChanges(node, editor);
OnChangesApplied();
}
internal void DoDisposeEditor(Control editor)
{
DisposeEditor(editor);
}
protected abstract void DoApplyChanges(TreeNodeAdv node, Control editor);
protected abstract Control CreateEditor(TreeNodeAdv node);
protected abstract void DisposeEditor(Control editor);
public virtual void Cut(Control control)
{
}
public virtual void Copy(Control control)
{
}
public virtual void Paste(Control control)
{
}
public virtual void Delete(Control control)
{
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
_editFlag = (!EditOnClick && args.Button == MouseButtons.Left
&& args.ModifierKeys == Keys.None && args.Node.IsSelected);
}
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
{
if (args.Node.IsSelected)
{
if (EditOnClick && args.Button == MouseButtons.Left && args.ModifierKeys == Keys.None)
{
Parent.ItemDragMode = false;
BeginEdit();
args.Handled = true;
}
else if (_editFlag)// && args.Node.IsSelected)
_timer.Start();
}
}
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
{
_editFlag = false;
_timer.Stop();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_timer.Dispose();
}
#region Events
public event CancelEventHandler EditorShowing;
protected void OnEditorShowing(CancelEventArgs args)
{
if (EditorShowing != null)
EditorShowing(this, args);
}
public event EventHandler EditorHided;
protected void OnEditorHided()
{
if (EditorHided != null)
EditorHided(this, EventArgs.Empty);
}
public event EventHandler ChangesApplied;
protected void OnChangesApplied()
{
if (ChangesApplied != null)
ChangesApplied(this, EventArgs.Empty);
}
#endregion
}
}

View File

@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace Aga.Controls.Tree.NodeControls
{
/// <summary>
/// Displays an animated icon for those nodes, who are in expanding state.
/// Parent TreeView must have AsyncExpanding property set to true.
/// </summary>
public class ExpandingIcon: NodeControl
{
private static GifDecoder _gif = ResourceHelper.LoadingIcon;
private static int _index = 0;
private static volatile Thread _animatingThread;
private static object _lock = new object();
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{
return ResourceHelper.LoadingIcon.FrameSize;
}
protected override void OnIsVisibleValueNeeded(NodeControlValueEventArgs args)
{
args.Value = args.Node.IsExpandingNow;
base.OnIsVisibleValueNeeded(args);
}
public override void Draw(TreeNodeAdv node, DrawContext context)
{
Rectangle rect = GetBounds(node, context);
Image img = _gif.GetFrame(_index).Image;
context.Graphics.DrawImage(img, rect.Location);
}
public static void Start()
{
lock (_lock)
{
if (_animatingThread == null)
{
_index = 0;
_animatingThread = new Thread(new ThreadStart(IterateIcons));
_animatingThread.IsBackground = true;
_animatingThread.Priority = ThreadPriority.Lowest;
_animatingThread.Start();
}
}
}
public static void Stop()
{
lock (_lock)
{
_index = 0;
_animatingThread = null;
}
}
private static void IterateIcons()
{
while (_animatingThread != null)
{
if (_index < _gif.FrameCount - 1)
_index++;
else
_index = 0;
if (IconChanged != null)
IconChanged(null, EventArgs.Empty);
int delay = _gif.GetFrame(_index).Delay;
Thread.Sleep(delay);
}
System.Diagnostics.Debug.WriteLine("IterateIcons Stopped");
}
public static event EventHandler IconChanged;
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public abstract class InteractiveControl : BindableControl
{
private bool _editEnabled = false;
[DefaultValue(false)]
public bool EditEnabled
{
get { return _editEnabled; }
set { _editEnabled = value; }
}
protected bool IsEditEnabled(TreeNodeAdv node)
{
if (EditEnabled)
{
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
args.Value = true;
OnIsEditEnabledValueNeeded(args);
return Convert.ToBoolean(args.Value);
}
else
return false;
}
public event EventHandler<NodeControlValueEventArgs> IsEditEnabledValueNeeded;
private void OnIsEditEnabledValueNeeded(NodeControlValueEventArgs args)
{
if (IsEditEnabledValueNeeded != null)
IsEditEnabledValueNeeded(this, args);
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree.NodeControls
{
public class LabelEventArgs : EventArgs
{
private object _subject;
public object Subject
{
get { return _subject; }
}
private string _oldLabel;
public string OldLabel
{
get { return _oldLabel; }
}
private string _newLabel;
public string NewLabel
{
get { return _newLabel; }
}
public LabelEventArgs(object subject, string oldLabel, string newLabel)
{
_subject = subject;
_oldLabel = oldLabel;
_newLabel = newLabel;
}
}
}

View File

@@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Aga.Controls.Properties;
using System.Reflection;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeCheckBox : InteractiveControl
{
public const int ImageSize = 13;
private Bitmap _check;
private Bitmap _uncheck;
private Bitmap _unknown;
#region Properties
private bool _threeState;
[DefaultValue(false)]
public bool ThreeState
{
get { return _threeState; }
set { _threeState = value; }
}
#endregion
public NodeCheckBox()
: this(string.Empty)
{
}
public NodeCheckBox(string propertyName)
{
_check = Resources.check;
_uncheck = Resources.uncheck;
_unknown = Resources.unknown;
DataPropertyName = propertyName;
LeftMargin = 0;
}
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
int scaledY = node.Tree.GetScaledSize(ImageSize);
return new Size(scaledX, scaledY);
}
public override void Draw(TreeNodeAdv node, DrawContext context)
{
Rectangle bounds = GetBounds(node, context);
CheckState state = GetCheckState(node);
if (TreeViewAdv.CustomCheckRenderFunc != null)
{
TreeViewAdv.CustomCheckRenderFunc(context.Graphics, bounds, state == CheckState.Checked);
}
else if (Application.RenderWithVisualStyles)
{
VisualStyleRenderer renderer;
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
int scaledY = node.Tree.GetScaledSize(ImageSize);
if (state == CheckState.Indeterminate)
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.MixedNormal);
else if (state == CheckState.Checked)
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal);
else
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal);
renderer.DrawBackground(context.Graphics, new Rectangle(bounds.X, bounds.Y, scaledX, scaledY));
}
else
{
Image img;
if (state == CheckState.Indeterminate)
img = _unknown;
else if (state == CheckState.Checked)
img = _check;
else
img = _uncheck;
context.Graphics.DrawImage(img, bounds.Location);
}
}
protected virtual CheckState GetCheckState(TreeNodeAdv node)
{
object obj = GetValue(node);
if (obj is CheckState)
return (CheckState)obj;
else if (obj is bool)
return (bool)obj ? CheckState.Checked : CheckState.Unchecked;
else
return CheckState.Unchecked;
}
protected virtual void SetCheckState(TreeNodeAdv node, CheckState value)
{
if (VirtualMode)
{
SetValue(node, value);
OnCheckStateChanged(node);
}
else
{
Type type = GetPropertyType(node);
if (type == typeof(CheckState))
{
SetValue(node, value);
OnCheckStateChanged(node);
}
else if (type == typeof(bool))
{
SetValue(node, value != CheckState.Unchecked);
OnCheckStateChanged(node);
}
}
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
if (args.Button == MouseButtons.Left && IsEditEnabled(args.Node))
{
DrawContext context = new DrawContext();
context.Bounds = args.ControlBounds;
Rectangle rect = GetBounds(args.Node, context);
if (rect.Contains(args.ViewLocation))
{
CheckState state = GetCheckState(args.Node);
state = GetNewState(state);
SetCheckState(args.Node, state);
Parent.UpdateView();
args.Handled = true;
}
}
}
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
{
args.Handled = true;
}
private CheckState GetNewState(CheckState state)
{
if (state == CheckState.Indeterminate)
return CheckState.Unchecked;
else if(state == CheckState.Unchecked)
return CheckState.Checked;
else
return ThreeState ? CheckState.Indeterminate : CheckState.Unchecked;
}
public override void KeyDown(KeyEventArgs args)
{
if (args.KeyCode == Keys.Space && EditEnabled)
{
Parent.BeginUpdate();
try
{
if (Parent.CurrentNode != null)
{
CheckState value = GetNewState(GetCheckState(Parent.CurrentNode));
foreach (TreeNodeAdv node in Parent.Selection)
if (IsEditEnabled(node))
SetCheckState(node, value);
}
}
finally
{
Parent.EndUpdate();
}
args.Handled = true;
}
}
public event EventHandler<TreePathEventArgs> CheckStateChanged;
protected void OnCheckStateChanged(TreePathEventArgs args)
{
if (CheckStateChanged != null)
CheckStateChanged(this, args);
}
protected void OnCheckStateChanged(TreeNodeAdv node)
{
TreePath path = this.Parent.GetPath(node);
OnCheckStateChanged(new TreePathEventArgs(path));
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
using System.Drawing.Design;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeComboBox : BaseTextControl
{
#region Properties
private int _editorWidth = 100;
[DefaultValue(100)]
public int EditorWidth
{
get { return _editorWidth; }
set { _editorWidth = value; }
}
private int _editorHeight = 100;
[DefaultValue(100)]
public int EditorHeight
{
get { return _editorHeight; }
set { _editorHeight = value; }
}
private List<object> _dropDownItems;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]
[Editor(typeof(StringCollectionEditor), typeof(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<object> DropDownItems
{
get { return _dropDownItems; }
}
#endregion
public event EventHandler<EditEventArgs> CreatingEditor;
public NodeComboBox()
{
_dropDownItems = new List<object>();
}
protected override Size CalculateEditorSize(EditorContext context)
{
if (Parent.UseColumns)
{
if (context.Editor is CheckedListBox)
return new Size(context.Bounds.Size.Width, EditorHeight);
else
return context.Bounds.Size;
}
else
{
if (context.Editor is CheckedListBox)
return new Size(EditorWidth, EditorHeight);
else
return new Size(EditorWidth, context.Bounds.Height);
}
}
protected override Control CreateEditor(TreeNodeAdv node)
{
Control c;
object value = GetValue(node);
if (IsCheckedListBoxRequired(node))
c = CreateCheckedListBox(node);
else
c = CreateCombo(node);
OnCreatingEditor(new EditEventArgs(node, c));
return c;
}
protected override void DisposeEditor(Control editor)
{
}
protected virtual void OnCreatingEditor(EditEventArgs args)
{
if (CreatingEditor != null)
CreatingEditor(this, args);
}
protected virtual bool IsCheckedListBoxRequired(TreeNodeAdv node)
{
object value = GetValue(node);
if (value != null)
{
Type t = value.GetType();
object[] arr = t.GetCustomAttributes(typeof(FlagsAttribute), false);
return (t.IsEnum && arr.Length == 1);
}
return false;
}
private Control CreateCombo(TreeNodeAdv node)
{
ComboBox comboBox = new ComboBox();
if (DropDownItems != null)
comboBox.Items.AddRange(DropDownItems.ToArray());
comboBox.SelectedItem = GetValue(node);
comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox.DropDownClosed += new EventHandler(EditorDropDownClosed);
SetEditControlProperties(comboBox, node);
return comboBox;
}
private Control CreateCheckedListBox(TreeNodeAdv node)
{
CheckedListBox listBox = new CheckedListBox();
listBox.CheckOnClick = true;
object value = GetValue(node);
Type enumType = GetEnumType(node);
foreach (object obj in Enum.GetValues(enumType))
{
object[] attributes = enumType.GetField(obj.ToString()).GetCustomAttributes(typeof(BrowsableAttribute), false);
if (attributes.Length == 0 || ((BrowsableAttribute)attributes[0]).Browsable)
listBox.Items.Add(obj, IsContain(value, obj));
}
SetEditControlProperties(listBox, node);
if (CreatingEditor != null)
CreatingEditor(this, new EditEventArgs(node, listBox));
return listBox;
}
protected virtual Type GetEnumType(TreeNodeAdv node)
{
object value = GetValue(node);
return value.GetType();
}
private bool IsContain(object value, object enumElement)
{
if (value == null || enumElement == null)
return false;
if (value.GetType().IsEnum)
{
int i1 = (int)value;
int i2 = (int)enumElement;
return (i1 & i2) == i2;
}
else
{
var arr = value as object[];
foreach (object obj in arr)
if ((int)obj == (int)enumElement)
return true;
return false;
}
}
protected override string FormatLabel(object obj)
{
var arr = obj as object[];
if (arr != null)
{
StringBuilder sb = new StringBuilder();
foreach (object t in arr)
{
if (sb.Length > 0)
sb.Append(", ");
sb.Append(t);
}
return sb.ToString();
}
else
return base.FormatLabel(obj);
}
void EditorDropDownClosed(object sender, EventArgs e)
{
EndEdit(true);
}
public override void UpdateEditor(Control control)
{
if (control is ComboBox)
(control as ComboBox).DroppedDown = true;
}
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
{
var combo = editor as ComboBox;
if (combo != null)
{
if (combo.DropDownStyle == ComboBoxStyle.DropDown)
SetValue(node, combo.Text);
else
SetValue(node, combo.SelectedItem);
}
else
{
var listBox = editor as CheckedListBox;
Type type = GetEnumType(node);
if (IsFlags(type))
{
int res = 0;
foreach (object obj in listBox.CheckedItems)
res |= (int)obj;
object val = Enum.ToObject(type, res);
SetValue(node, val);
}
else
{
List<object> list = new List<object>();
foreach (object obj in listBox.CheckedItems)
list.Add(obj);
SetValue(node, list.ToArray());
}
}
}
private bool IsFlags(Type type)
{
object[] atr = type.GetCustomAttributes(typeof(FlagsAttribute), false);
return atr.Length == 1;
}
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
{
if (args.Node != null && args.Node.IsSelected) //Workaround of specific ComboBox control behavior
base.MouseUp(args);
}
}
}

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
[DesignTimeVisible(false), ToolboxItem(false)]
public abstract class NodeControl : Component
{
#region Properties
private TreeViewAdv _parent;
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public TreeViewAdv Parent
{
get { return _parent; }
set
{
if (value != _parent)
{
if (_parent != null)
_parent.NodeControls.Remove(this);
if (value != null)
value.NodeControls.Add(this);
}
}
}
private IToolTipProvider _toolTipProvider;
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IToolTipProvider ToolTipProvider
{
get { return _toolTipProvider; }
set { _toolTipProvider = value; }
}
private TreeColumn _parentColumn;
public TreeColumn ParentColumn
{
get { return _parentColumn; }
set
{
_parentColumn = value;
if (_parent != null)
_parent.FullUpdate();
}
}
private VerticalAlignment _verticalAlign = VerticalAlignment.Center;
[DefaultValue(VerticalAlignment.Center)]
public VerticalAlignment VerticalAlign
{
get { return _verticalAlign; }
set
{
_verticalAlign = value;
if (_parent != null)
_parent.FullUpdate();
}
}
private int _leftMargin = 0;
public int LeftMargin
{
get { return _leftMargin; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException();
_leftMargin = value;
if (_parent != null)
_parent.FullUpdate();
}
}
#endregion
internal virtual void AssignParent(TreeViewAdv parent)
{
_parent = parent;
}
protected virtual Rectangle GetBounds(TreeNodeAdv node, DrawContext context)
{
Rectangle r = context.Bounds;
Size s = GetActualSize(node, context);
Size bs = new Size(r.Width - LeftMargin, Math.Min(r.Height, s.Height));
switch (VerticalAlign)
{
case VerticalAlignment.Top:
return new Rectangle(new Point(r.X + LeftMargin, r.Y), bs);
case VerticalAlignment.Bottom:
return new Rectangle(new Point(r.X + LeftMargin, r.Bottom - s.Height), bs);
default:
return new Rectangle(new Point(r.X + LeftMargin, r.Y + (r.Height - s.Height) / 2), bs);
}
}
protected void CheckThread()
{
if (Parent != null && Control.CheckForIllegalCrossThreadCalls)
if (Parent.InvokeRequired)
throw new InvalidOperationException("Cross-thread calls are not allowed");
}
public bool IsVisible(TreeNodeAdv node)
{
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
args.Value = true;
OnIsVisibleValueNeeded(args);
return Convert.ToBoolean(args.Value);
}
internal Size GetActualSize(TreeNodeAdv node, DrawContext context)
{
if (IsVisible(node))
{
Size s = MeasureSize(node, context);
return new Size(s.Width + LeftMargin, s.Height);
}
else
return Size.Empty;
}
public abstract Size MeasureSize(TreeNodeAdv node, DrawContext context);
public abstract void Draw(TreeNodeAdv node, DrawContext context);
public virtual string GetToolTip(TreeNodeAdv node)
{
if (ToolTipProvider != null)
return ToolTipProvider.GetToolTip(node, this);
else
return string.Empty;
}
public virtual void MouseDown(TreeNodeAdvMouseEventArgs args)
{
}
public virtual void MouseUp(TreeNodeAdvMouseEventArgs args)
{
}
public virtual void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
{
}
public virtual void KeyDown(KeyEventArgs args)
{
}
public virtual void KeyUp(KeyEventArgs args)
{
}
public event EventHandler<NodeControlValueEventArgs> IsVisibleValueNeeded;
protected virtual void OnIsVisibleValueNeeded(NodeControlValueEventArgs args)
{
if (IsVisibleValueNeeded != null)
IsVisibleValueNeeded(this, args);
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeControlValueEventArgs : NodeEventArgs
{
private object _value;
public object Value
{
get { return _value; }
set { _value = value; }
}
public NodeControlValueEventArgs(TreeNodeAdv node)
:base(node)
{
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing.Design;
namespace Aga.Controls.Tree.NodeControls
{
internal class NodeControlsCollection : Collection<NodeControl>
{
private TreeViewAdv _tree;
public NodeControlsCollection(TreeViewAdv tree)
{
_tree = tree;
}
protected override void ClearItems()
{
_tree.BeginUpdate();
try
{
while (this.Count != 0)
this.RemoveAt(this.Count - 1);
}
finally
{
_tree.EndUpdate();
}
}
protected override void InsertItem(int index, NodeControl item)
{
if (item == null)
throw new ArgumentNullException("item");
if (item.Parent != _tree)
{
if (item.Parent != null)
{
item.Parent.NodeControls.Remove(item);
}
base.InsertItem(index, item);
item.AssignParent(_tree);
_tree.FullUpdate();
}
}
protected override void RemoveItem(int index)
{
NodeControl value = this[index];
value.AssignParent(null);
base.RemoveItem(index);
_tree.FullUpdate();
}
protected override void SetItem(int index, NodeControl item)
{
if (item == null)
throw new ArgumentNullException("item");
_tree.BeginUpdate();
try
{
RemoveAt(index);
InsertItem(index, item);
}
finally
{
_tree.EndUpdate();
}
}
}
internal class NodeControlCollectionEditor : CollectionEditor
{
private Type[] _types;
public NodeControlCollectionEditor(Type type)
: base(type)
{
_types = new Type[] { typeof(NodeTextBox), typeof(NodeIntegerTextBox), typeof(NodeDecimalTextBox),
typeof(NodeComboBox), typeof(NodeCheckBox),
typeof(NodeStateIcon), typeof(NodeIcon), typeof(NodeNumericUpDown), typeof(ExpandingIcon) };
}
protected override System.Type[] CreateNewItemTypes()
{
return _types;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeDecimalTextBox : NodeTextBox
{
private bool _allowDecimalSeparator = true;
[DefaultValue(true)]
public bool AllowDecimalSeparator
{
get { return _allowDecimalSeparator; }
set { _allowDecimalSeparator = value; }
}
private bool _allowNegativeSign = true;
[DefaultValue(true)]
public bool AllowNegativeSign
{
get { return _allowNegativeSign; }
set { _allowNegativeSign = value; }
}
protected NodeDecimalTextBox()
{
}
protected override TextBox CreateTextBox()
{
NumericTextBox textBox = new NumericTextBox();
textBox.AllowDecimalSeparator = AllowDecimalSeparator;
textBox.AllowNegativeSign = AllowNegativeSign;
return textBox;
}
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
{
SetValue(node, (editor as NumericTextBox).DecimalValue);
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeEventArgs : EventArgs
{
private TreeNodeAdv _node;
public TreeNodeAdv Node
{
get { return _node; }
}
public NodeEventArgs(TreeNodeAdv node)
{
_node = node;
}
}
}

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using Aga.Controls.Properties;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeIcon : BindableControl
{
public NodeIcon()
{
LeftMargin = 1;
}
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{
Image image = GetIcon(node);
if (image != null)
{
int scaledX = node.Tree.GetScaledSize(image.Size.Width, false);
int scaledY = node.Tree.GetScaledSize(image.Size.Height);
return new Size(scaledX, scaledY); ;
}
else
{
return Size.Empty;
}
}
public override void Draw(TreeNodeAdv node, DrawContext context)
{
Image image = GetIcon(node);
if (image != null)
{
Rectangle r = GetBounds(node, context);
if ( image.Width > 0 && image.Height > 0 )
{
switch (_scaleMode)
{
case ImageScaleMode.Fit:
context.Graphics.DrawImage(image, r);
break;
case ImageScaleMode.ScaleDown:
{
float factor = Math.Min((float)r.Width / (float)image.Width, (float)r.Height / (float)image.Height);
if (factor < 1)
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
else
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
} break;
case ImageScaleMode.ScaleUp:
{
float factor = Math.Max((float)r.Width / (float)image.Width, (float)r.Height / (float)image.Height);
if (factor > 1)
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
else
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
} break;
case ImageScaleMode.AlwaysScale:
{
float fx = (float)r.Width / (float)image.Width;
float fy = (float)r.Height / (float)image.Height;
if (Math.Min(fx, fy) < 1)
{ //scale down
float factor = Math.Min(fx, fy);
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
}
else if (Math.Max(fx, fy) > 1)
{
float factor = Math.Max(fx, fy);
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
}
else
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
} break;
case ImageScaleMode.Clip:
default:
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
break;
}
}
}
}
protected virtual Image GetIcon(TreeNodeAdv node)
{
return GetValue(node) as Image;
}
private ImageScaleMode _scaleMode = ImageScaleMode.Clip;
[DefaultValue("Clip"), Category("Appearance")]
public ImageScaleMode ScaleMode
{
get { return _scaleMode; }
set { _scaleMode = value; }
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeIntegerTextBox : NodeTextBox
{
private bool _allowNegativeSign = true;
[DefaultValue(true)]
public bool AllowNegativeSign
{
get { return _allowNegativeSign; }
set { _allowNegativeSign = value; }
}
public NodeIntegerTextBox()
{
}
protected override TextBox CreateTextBox()
{
NumericTextBox textBox = new NumericTextBox();
textBox.AllowDecimalSeparator = false;
textBox.AllowNegativeSign = AllowNegativeSign;
return textBox;
}
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
{
SetValue(node, (editor as NumericTextBox).IntValue);
}
}
}

View File

@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
using System.Drawing.Design;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeNumericUpDown : BaseTextControl
{
#region Properties
private int _editorWidth = 100;
[DefaultValue(100)]
public int EditorWidth
{
get { return _editorWidth; }
set { _editorWidth = value; }
}
private int _decimalPlaces = 0;
[Category("Data"), DefaultValue(0)]
public int DecimalPlaces
{
get
{
return this._decimalPlaces;
}
set
{
this._decimalPlaces = value;
}
}
private decimal _increment = 1;
[Category("Data"), DefaultValue(1)]
public decimal Increment
{
get
{
return this._increment;
}
set
{
this._increment = value;
}
}
private decimal _minimum = 0;
[Category("Data"), DefaultValue(0)]
public decimal Minimum
{
get
{
return _minimum;
}
set
{
_minimum = value;
}
}
private decimal _maximum = 100;
[Category("Data"), DefaultValue(100)]
public decimal Maximum
{
get
{
return this._maximum;
}
set
{
this._maximum = value;
}
}
#endregion
public NodeNumericUpDown()
{
}
protected override Size CalculateEditorSize(EditorContext context)
{
if (Parent.UseColumns)
return context.Bounds.Size;
else
return new Size(EditorWidth, context.Bounds.Height);
}
protected override Control CreateEditor(TreeNodeAdv node)
{
NumericUpDown num = new NumericUpDown();
num.Increment = Increment;
num.DecimalPlaces = DecimalPlaces;
num.Minimum = Minimum;
num.Maximum = Maximum;
num.Value = (decimal)GetValue(node);
SetEditControlProperties(num, node);
return num;
}
protected override void DisposeEditor(Control editor)
{
}
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
{
SetValue(node, (editor as NumericUpDown).Value);
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Aga.Controls.Properties;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace Aga.Controls.Tree.NodeControls
{
internal class NodePlusMinus : NodeControl
{
public const int ImageSize = 9;
public const int Width = 16;
private Bitmap _plus;
private Bitmap _minus;
private VisualStyleRenderer _openedRenderer;
private VisualStyleRenderer OpenedRenderer
{
get
{
if (_openedRenderer == null)
_openedRenderer = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened);
return _openedRenderer;
}
}
private VisualStyleRenderer _closedRenderer;
private VisualStyleRenderer ClosedRenderer
{
get
{
if (_closedRenderer == null)
_closedRenderer = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Closed);
return _closedRenderer;
}
}
public NodePlusMinus()
{
_plus = Resources.plus;
_minus = Resources.minus;
}
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
{
int scaledX = node.Tree.GetScaledSize(Width, false);
int scaledY = node.Tree.GetScaledSize(Width);
return new Size(scaledX, scaledY);
}
public override void Draw(TreeNodeAdv node, DrawContext context)
{
if (node.CanExpand)
{
Rectangle r = context.Bounds;
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
int scaledY = node.Tree.GetScaledSize(ImageSize);
int dy = (int)Math.Round((float)(r.Height - scaledY) / 2);
if (TreeViewAdv.CustomPlusMinusRenderFunc != null)
{
TreeViewAdv.CustomPlusMinusRenderFunc(context.Graphics, r, node.IsExpanded);
return;
}
else if (Application.RenderWithVisualStyles)
{
VisualStyleRenderer renderer;
if (node.IsExpanded)
renderer = OpenedRenderer;
else
renderer = ClosedRenderer;
renderer.DrawBackground(context.Graphics, new Rectangle(r.X, r.Y + dy, scaledX, scaledY));
}
else
{
Image img;
if (node.IsExpanded)
img = _minus;
else
img = _plus;
context.Graphics.DrawImageUnscaled(img, new Point(r.X, r.Y + dy));
}
}
}
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
{
if (args.Button == MouseButtons.Left)
{
args.Handled = true;
if (args.Node.CanExpand)
args.Node.IsExpanded = !args.Node.IsExpanded;
}
}
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
{
args.Handled = true; // Supress expand/collapse when double click on plus/minus
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Aga.Controls.Properties;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeStateIcon: NodeIcon
{
private Image _leaf;
private Image _opened;
private Image _closed;
public NodeStateIcon()
{
_leaf = MakeTransparent(Resources.Leaf);
_opened = MakeTransparent(Resources.Folder);
_closed = MakeTransparent(Resources.FolderClosed);
}
private static Image MakeTransparent(Bitmap bitmap)
{
bitmap.MakeTransparent(bitmap.GetPixel(0,0));
return bitmap;
}
protected override Image GetIcon(TreeNodeAdv node)
{
Image icon = base.GetIcon(node);
if (icon != null)
return icon;
else if (node.IsLeaf)
return _leaf;
else if (node.CanExpand && node.IsExpanded)
return _opened;
else
return _closed;
}
}
}

View File

@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Reflection;
using System.ComponentModel;
namespace Aga.Controls.Tree.NodeControls
{
public class NodeTextBox : BaseTextControl
{
private const int MinTextBoxWidth = 30;
public NodeTextBox()
{
}
protected override Size CalculateEditorSize(EditorContext context)
{
if (Parent.UseColumns)
return context.Bounds.Size;
else
{
Size size = GetLabelSize(context.CurrentNode, context.DrawContext, _label);
int width = Math.Max(size.Width + Font.Height, MinTextBoxWidth); // reserve a place for new typed character
return new Size(width, size.Height);
}
}
public override void KeyDown(KeyEventArgs args)
{
if (args.KeyCode == Keys.F2 && Parent.CurrentNode != null && EditEnabled)
{
args.Handled = true;
BeginEdit();
}
}
protected override Control CreateEditor(TreeNodeAdv node)
{
TextBox textBox = CreateTextBox();
textBox.TextAlign = TextAlign;
textBox.Text = GetLabel(node);
textBox.BorderStyle = BorderStyle.FixedSingle;
textBox.TextChanged += EditorTextChanged;
textBox.KeyDown += EditorKeyDown;
_label = textBox.Text;
SetEditControlProperties(textBox, node);
return textBox;
}
protected virtual TextBox CreateTextBox()
{
return new TextBox();
}
protected override void DisposeEditor(Control editor)
{
var textBox = editor as TextBox;
textBox.TextChanged -= EditorTextChanged;
textBox.KeyDown -= EditorKeyDown;
}
private void EditorKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
EndEdit(false);
else if (e.KeyCode == Keys.Enter)
EndEdit(true);
}
private string _label;
private void EditorTextChanged(object sender, EventArgs e)
{
var textBox = sender as TextBox;
_label = textBox.Text;
Parent.UpdateEditorBounds();
}
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
{
var label = (editor as TextBox).Text;
string oldLabel = GetLabel(node);
if (oldLabel != label)
{
SetLabel(node, label);
OnLabelChanged(node.Tag, oldLabel, label);
}
}
public override void Cut(Control control)
{
(control as TextBox).Cut();
}
public override void Copy(Control control)
{
(control as TextBox).Copy();
}
public override void Paste(Control control)
{
(control as TextBox).Paste();
}
public override void Delete(Control control)
{
var textBox = control as TextBox;
int len = Math.Max(textBox.SelectionLength, 1);
if (textBox.SelectionStart < textBox.Text.Length)
{
int start = textBox.SelectionStart;
textBox.Text = textBox.Text.Remove(textBox.SelectionStart, len);
textBox.SelectionStart = start;
}
}
public event EventHandler<LabelEventArgs> LabelChanged;
protected void OnLabelChanged(object subject, string oldLabel, string newLabel)
{
if (LabelChanged != null)
LabelChanged(this, new LabelEventArgs(subject, oldLabel, newLabel));
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace Aga.Controls.Tree
{
public class SortedTreeModel: TreeModelBase
{
private ITreeModel _innerModel;
public ITreeModel InnerModel
{
get { return _innerModel; }
}
private IComparer _comparer;
public IComparer Comparer
{
get { return _comparer; }
set
{
_comparer = value;
OnStructureChanged(new TreePathEventArgs(TreePath.Empty));
}
}
public SortedTreeModel(ITreeModel innerModel)
{
_innerModel = innerModel;
_innerModel.NodesChanged += new EventHandler<TreeModelEventArgs>(_innerModel_NodesChanged);
_innerModel.NodesInserted += new EventHandler<TreeModelEventArgs>(_innerModel_NodesInserted);
_innerModel.NodesRemoved += new EventHandler<TreeModelEventArgs>(_innerModel_NodesRemoved);
_innerModel.StructureChanged += new EventHandler<TreePathEventArgs>(_innerModel_StructureChanged);
}
void _innerModel_StructureChanged(object sender, TreePathEventArgs e)
{
OnStructureChanged(e);
}
void _innerModel_NodesRemoved(object sender, TreeModelEventArgs e)
{
OnStructureChanged(new TreePathEventArgs(e.Path));
}
void _innerModel_NodesInserted(object sender, TreeModelEventArgs e)
{
OnStructureChanged(new TreePathEventArgs(e.Path));
}
void _innerModel_NodesChanged(object sender, TreeModelEventArgs e)
{
OnStructureChanged(new TreePathEventArgs(e.Path));
}
public override IEnumerable GetChildren(TreePath treePath)
{
if (Comparer != null)
{
ArrayList list = new ArrayList();
IEnumerable res = InnerModel.GetChildren(treePath);
if (res != null)
{
foreach (object obj in res)
list.Add(obj);
list.Sort(Comparer);
return list;
}
else
return null;
}
else
return InnerModel.GetChildren(treePath);
}
public override bool IsLeaf(TreePath treePath)
{
return InnerModel.IsLeaf(treePath);
}
}
}

View File

@@ -0,0 +1,385 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using System.Drawing.Imaging;
namespace Aga.Controls.Tree
{
[TypeConverter(typeof(TreeColumn.TreeColumnConverter)), DesignTimeVisible(false), ToolboxItem(false)]
public class TreeColumn : Component
{
private class TreeColumnConverter : ComponentConverter
{
public TreeColumnConverter()
: base(typeof(TreeColumn))
{
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return false;
}
}
private const int HeaderLeftMargin = 5;
private const int HeaderRightMargin = 5;
private const int SortOrderMarkMargin = 8;
private TextFormatFlags _headerFlags;
private TextFormatFlags _baseHeaderFlags = TextFormatFlags.NoPadding |
TextFormatFlags.EndEllipsis |
TextFormatFlags.VerticalCenter |
TextFormatFlags.PreserveGraphicsTranslateTransform;
#region Properties
private TreeColumnCollection _owner;
internal TreeColumnCollection Owner
{
get { return _owner; }
set { _owner = value; }
}
[Browsable(false)]
public int Index
{
get
{
if (Owner != null)
return Owner.IndexOf(this);
else
return -1;
}
}
private string _header;
[Localizable(true)]
public string Header
{
get { return _header; }
set
{
_header = value;
OnHeaderChanged();
}
}
private string _tooltipText;
[Localizable(true)]
public string TooltipText
{
get { return _tooltipText; }
set { _tooltipText = value; }
}
private int _width;
[DefaultValue(50), Localizable(true)]
public int Width
{
get
{
return _width;
}
set
{
if (_width != value)
{
_width = Math.Max(MinColumnWidth, value);
if (_maxColumnWidth > 0)
{
_width = Math.Min(_width, MaxColumnWidth);
}
OnWidthChanged();
}
}
}
private int _minColumnWidth;
[DefaultValue(0)]
public int MinColumnWidth
{
get { return _minColumnWidth; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("value");
_minColumnWidth = value;
Width = Math.Max(value, Width);
}
}
private int _maxColumnWidth;
[DefaultValue(0)]
public int MaxColumnWidth
{
get { return _maxColumnWidth; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("value");
_maxColumnWidth = value;
if (value > 0)
Width = Math.Min(value, _width);
}
}
private bool _visible = true;
[DefaultValue(true)]
public bool IsVisible
{
get { return _visible; }
set
{
_visible = value;
OnIsVisibleChanged();
}
}
private HorizontalAlignment _textAlign = HorizontalAlignment.Left;
[DefaultValue(HorizontalAlignment.Left)]
public HorizontalAlignment TextAlign
{
get { return _textAlign; }
set
{
if (value != _textAlign)
{
_textAlign = value;
_headerFlags = _baseHeaderFlags | TextHelper.TranslateAligmentToFlag(value);
OnHeaderChanged();
}
}
}
private bool _sortable = false;
[DefaultValue(false)]
public bool Sortable
{
get { return _sortable; }
set { _sortable = value; }
}
private SortOrder _sort_order = SortOrder.None;
public SortOrder SortOrder
{
get { return _sort_order; }
set
{
if (value == _sort_order)
return;
_sort_order = value;
OnSortOrderChanged();
}
}
public Size SortMarkSize
{
get
{
if (Application.RenderWithVisualStyles)
return new Size(9, 5);
else
return new Size(7, 4);
}
}
#endregion
public TreeColumn():
this(string.Empty, 50)
{
}
public TreeColumn(string header, int width)
{
_header = header;
_width = width;
_headerFlags = _baseHeaderFlags | TextFormatFlags.Left;
}
public override string ToString()
{
if (string.IsNullOrEmpty(Header))
return GetType().Name;
else
return Header;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
#region Draw
private static VisualStyleRenderer _normalRenderer;
private static VisualStyleRenderer _pressedRenderer;
private static VisualStyleRenderer _hotRenderer;
private static void CreateRenderers()
{
if (Application.RenderWithVisualStyles && _normalRenderer == null)
{
_normalRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Normal);
_pressedRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Pressed);
_hotRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Hot);
}
}
internal Bitmap CreateGhostImage(Rectangle bounds, Font font)
{
Bitmap b = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
Graphics gr = Graphics.FromImage(b);
gr.FillRectangle(SystemBrushes.ControlDark, bounds);
DrawContent(gr, bounds, font);
BitmapHelper.SetAlphaChanelValue(b, 150);
return b;
}
internal void Draw(Graphics gr, Rectangle bounds, Font font, bool pressed, bool hot)
{
DrawBackground(gr, bounds, pressed, hot);
DrawContent(gr, bounds, font);
}
private void DrawContent(Graphics gr, Rectangle bounds, Font font)
{
if (TreeViewAdv.CustomColumnTextRenderFunc != null)
{
TreeViewAdv.CustomColumnTextRenderFunc(gr, bounds, font, Header);
}
else
{
Rectangle innerBounds = new Rectangle(bounds.X + HeaderLeftMargin, bounds.Y,
bounds.Width - HeaderLeftMargin - HeaderRightMargin,
bounds.Height);
if (SortOrder != SortOrder.None)
innerBounds.Width -= (SortMarkSize.Width + SortOrderMarkMargin);
Size maxTextSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, TextFormatFlags.NoPadding);
Size textSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, _baseHeaderFlags);
if (SortOrder != SortOrder.None)
{
int tw = Math.Min(textSize.Width, innerBounds.Size.Width);
int x = 0;
if (TextAlign == HorizontalAlignment.Left)
x = innerBounds.X + tw + SortOrderMarkMargin;
else if (TextAlign == HorizontalAlignment.Right)
x = innerBounds.Right + SortOrderMarkMargin;
else
x = innerBounds.X + tw + (innerBounds.Width - tw) / 2 + SortOrderMarkMargin;
DrawSortMark(gr, bounds, x);
}
if (textSize.Width < maxTextSize.Width)
TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _baseHeaderFlags | TextFormatFlags.Left);
else
TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _headerFlags);
}
}
private void DrawSortMark(Graphics gr, Rectangle bounds, int x)
{
int y = bounds.Y + bounds.Height / 2 - 2;
x = Math.Max(x, bounds.X + SortOrderMarkMargin);
int w2 = SortMarkSize.Width / 2;
if (SortOrder == SortOrder.Ascending)
{
Point[] points = new Point[] { new Point(x, y), new Point(x + SortMarkSize.Width, y), new Point(x + w2, y + SortMarkSize.Height) };
gr.FillPolygon(SystemBrushes.ControlDark, points);
}
else if (SortOrder == SortOrder.Descending)
{
Point[] points = new Point[] { new Point(x - 1, y + SortMarkSize.Height), new Point(x + SortMarkSize.Width, y + SortMarkSize.Height), new Point(x + w2, y - 1) };
gr.FillPolygon(SystemBrushes.ControlDark, points);
}
}
internal static void DrawDropMark(Graphics gr, Rectangle rect)
{
gr.FillRectangle(SystemBrushes.HotTrack, rect.X-1, rect.Y, 2, rect.Height);
}
internal static void DrawBackground(Graphics gr, Rectangle bounds, bool pressed, bool hot)
{
if (TreeViewAdv.CustomColumnBackgroundRenderFunc != null)
{
TreeViewAdv.CustomColumnBackgroundRenderFunc(gr, bounds, pressed, hot);
}
else
{
if (Application.RenderWithVisualStyles)
{
CreateRenderers();
if (pressed)
_pressedRenderer.DrawBackground(gr, bounds);
else if (hot)
_hotRenderer.DrawBackground(gr, bounds);
else
_normalRenderer.DrawBackground(gr, bounds);
}
else
{
gr.FillRectangle(SystemBrushes.Control, bounds);
Pen p1 = SystemPens.ControlLightLight;
Pen p2 = SystemPens.ControlDark;
Pen p3 = SystemPens.ControlDarkDark;
if (pressed)
gr.DrawRectangle(p2, bounds.X, bounds.Y, bounds.Width, bounds.Height);
else
{
gr.DrawLine(p1, bounds.X, bounds.Y, bounds.Right, bounds.Y);
gr.DrawLine(p3, bounds.X, bounds.Bottom, bounds.Right, bounds.Bottom);
gr.DrawLine(p3, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 1);
gr.DrawLine(p1, bounds.Left, bounds.Y + 1, bounds.Left, bounds.Bottom - 2);
gr.DrawLine(p2, bounds.Right - 2, bounds.Y + 1, bounds.Right - 2, bounds.Bottom - 2);
gr.DrawLine(p2, bounds.X, bounds.Bottom - 1, bounds.Right - 2, bounds.Bottom - 1);
}
}
}
}
#endregion
#region Events
public event EventHandler HeaderChanged;
private void OnHeaderChanged()
{
if (HeaderChanged != null)
HeaderChanged(this, EventArgs.Empty);
}
public event EventHandler SortOrderChanged;
private void OnSortOrderChanged()
{
if (SortOrderChanged != null)
SortOrderChanged(this, EventArgs.Empty);
}
public event EventHandler IsVisibleChanged;
private void OnIsVisibleChanged()
{
if (IsVisibleChanged != null)
IsVisibleChanged(this, EventArgs.Empty);
}
public event EventHandler WidthChanged;
private void OnWidthChanged()
{
if (WidthChanged != null)
WidthChanged(this, EventArgs.Empty);
}
#endregion
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms;
namespace Aga.Controls.Tree
{
internal class TreeColumnCollection : Collection<TreeColumn>
{
private TreeViewAdv _treeView;
public TreeColumnCollection(TreeViewAdv treeView)
{
_treeView = treeView;
}
protected override void InsertItem(int index, TreeColumn item)
{
base.InsertItem(index, item);
BindEvents(item);
_treeView.UpdateColumns();
}
protected override void RemoveItem(int index)
{
UnbindEvents(this[index]);
base.RemoveItem(index);
_treeView.UpdateColumns();
}
protected override void SetItem(int index, TreeColumn item)
{
UnbindEvents(this[index]);
base.SetItem(index, item);
item.Owner = this;
BindEvents(item);
_treeView.UpdateColumns();
}
protected override void ClearItems()
{
foreach (TreeColumn c in Items)
UnbindEvents(c);
Items.Clear();
_treeView.UpdateColumns();
}
private void BindEvents(TreeColumn item)
{
item.Owner = this;
item.HeaderChanged += HeaderChanged;
item.IsVisibleChanged += IsVisibleChanged;
item.WidthChanged += WidthChanged;
item.SortOrderChanged += SortOrderChanged;
}
private void UnbindEvents(TreeColumn item)
{
item.Owner = null;
item.HeaderChanged -= HeaderChanged;
item.IsVisibleChanged -= IsVisibleChanged;
item.WidthChanged -= WidthChanged;
item.SortOrderChanged -= SortOrderChanged;
}
void SortOrderChanged(object sender, EventArgs e)
{
TreeColumn changed = sender as TreeColumn;
//Only one column at a time can have a sort property set
if (changed.SortOrder != SortOrder.None)
{
foreach (TreeColumn col in this)
{
if (col != changed)
col.SortOrder = SortOrder.None;
}
}
_treeView.UpdateHeaders();
}
void WidthChanged(object sender, EventArgs e)
{
_treeView.ChangeColumnWidth(sender as TreeColumn);
}
void IsVisibleChanged(object sender, EventArgs e)
{
_treeView.FullUpdate();
}
void HeaderChanged(object sender, EventArgs e)
{
_treeView.UpdateView();
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public class TreeColumnEventArgs: EventArgs
{
private TreeColumn _column;
public TreeColumn Column
{
get { return _column; }
}
public TreeColumnEventArgs(TreeColumn column)
{
_column = column;
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
/// <summary>
/// Converts IEnumerable interface to ITreeModel.
/// Allows to display a plain list in the TreeView
/// </summary>
public class TreeListAdapter : ITreeModel
{
private System.Collections.IEnumerable _list;
public TreeListAdapter(System.Collections.IEnumerable list)
{
_list = list;
}
#region ITreeModel Members
public System.Collections.IEnumerable GetChildren(TreePath treePath)
{
if (treePath.IsEmpty())
return _list;
else
return null;
}
public bool IsLeaf(TreePath treePath)
{
return true;
}
public event EventHandler<TreeModelEventArgs> NodesChanged;
public void OnNodesChanged(TreeModelEventArgs args)
{
if (NodesChanged != null)
NodesChanged(this, args);
}
public event EventHandler<TreePathEventArgs> StructureChanged;
public void OnStructureChanged(TreePathEventArgs args)
{
if (StructureChanged != null)
StructureChanged(this, args);
}
public event EventHandler<TreeModelEventArgs> NodesInserted;
public void OnNodeInserted(TreeModelEventArgs args)
{
if (NodesInserted != null)
NodesInserted(this, args);
}
public event EventHandler<TreeModelEventArgs> NodesRemoved;
public void OnNodeRemoved(TreeModelEventArgs args)
{
if (NodesRemoved != null)
NodesRemoved(this, args);
}
#endregion
}
}

View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
namespace Aga.Controls.Tree
{
/// <summary>
/// Provides a simple ready to use implementation of <see cref="ITreeModel"/>. Warning: this class is not optimized
/// to work with big amount of data. In this case create you own implementation of <c>ITreeModel</c>, and pay attention
/// on GetChildren and IsLeaf methods.
/// </summary>
public class TreeModel : ITreeModel
{
private Node _root;
public Node Root
{
get { return _root; }
}
public Collection<Node> Nodes
{
get { return _root.Nodes; }
}
public TreeModel()
{
_root = new Node();
_root.Model = this;
}
public TreePath GetPath(Node node)
{
if (node == _root)
return TreePath.Empty;
else
{
Stack<object> stack = new Stack<object>();
while (node != _root)
{
stack.Push(node);
node = node.Parent;
}
return new TreePath(stack.ToArray());
}
}
public Node FindNode(TreePath path)
{
if (path.IsEmpty())
return _root;
else
return FindNode(_root, path, 0);
}
private Node FindNode(Node root, TreePath path, int level)
{
foreach (Node node in root.Nodes)
if (node == path.FullPath[level])
{
if (level == path.FullPath.Length - 1)
return node;
else
return FindNode(node, path, level + 1);
}
return null;
}
#region ITreeModel Members
public System.Collections.IEnumerable GetChildren(TreePath treePath)
{
Node node = FindNode(treePath);
if (node != null)
foreach (Node n in node.Nodes)
yield return n;
else
yield break;
}
public bool IsLeaf(TreePath treePath)
{
Node node = FindNode(treePath);
if (node != null)
return node.IsLeaf;
else
throw new ArgumentException("treePath");
}
public event EventHandler<TreeModelEventArgs> NodesChanged;
internal void OnNodesChanged(TreeModelEventArgs args)
{
if (NodesChanged != null)
NodesChanged(this, args);
}
public event EventHandler<TreePathEventArgs> StructureChanged;
public void OnStructureChanged(TreePathEventArgs args)
{
if (StructureChanged != null)
StructureChanged(this, args);
}
public event EventHandler<TreeModelEventArgs> NodesInserted;
internal void OnNodeInserted(Node parent, int index, Node node)
{
if (NodesInserted != null)
{
TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node });
NodesInserted(this, args);
}
}
public event EventHandler<TreeModelEventArgs> NodesRemoved;
internal void OnNodeRemoved(Node parent, int index, Node node)
{
if (NodesRemoved != null)
{
TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node });
NodesRemoved(this, args);
}
}
#endregion
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public abstract class TreeModelBase: ITreeModel
{
public abstract System.Collections.IEnumerable GetChildren(TreePath treePath);
public abstract bool IsLeaf(TreePath treePath);
public event EventHandler<TreeModelEventArgs> NodesChanged;
protected void OnNodesChanged(TreeModelEventArgs args)
{
if (NodesChanged != null)
NodesChanged(this, args);
}
public event EventHandler<TreePathEventArgs> StructureChanged;
protected void OnStructureChanged(TreePathEventArgs args)
{
if (StructureChanged != null)
StructureChanged(this, args);
}
public event EventHandler<TreeModelEventArgs> NodesInserted;
protected void OnNodesInserted(TreeModelEventArgs args)
{
if (NodesInserted != null)
NodesInserted(this, args);
}
public event EventHandler<TreeModelEventArgs> NodesRemoved;
protected void OnNodesRemoved(TreeModelEventArgs args)
{
if (NodesRemoved != null)
NodesRemoved(this, args);
}
public virtual void Refresh()
{
OnStructureChanged(new TreePathEventArgs(TreePath.Empty));
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public class TreeModelEventArgs: TreePathEventArgs
{
private object[] _children;
public object[] Children
{
get { return _children; }
}
private int[] _indices;
public int[] Indices
{
get { return _indices; }
}
/// <summary>
///
/// </summary>
/// <param name="parent">Path to a parent node</param>
/// <param name="children">Child nodes</param>
public TreeModelEventArgs(TreePath parent, object[] children)
: this(parent, null, children)
{
}
/// <summary>
///
/// </summary>
/// <param name="parent">Path to a parent node</param>
/// <param name="indices">Indices of children in parent nodes collection</param>
/// <param name="children">Child nodes</param>
public TreeModelEventArgs(TreePath parent, int[] indices, object[] children)
: base(parent)
{
if (children == null)
throw new ArgumentNullException();
if (indices != null && indices.Length != children.Length)
throw new ArgumentException("indices and children arrays must have the same length");
_indices = indices;
_children = children;
}
}
}

View File

@@ -0,0 +1,443 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace Aga.Controls.Tree
{
[Serializable]
public sealed class TreeNodeAdv : ISerializable
{
#region NodeCollection
private class NodeCollection : Collection<TreeNodeAdv>
{
private TreeNodeAdv _owner;
public NodeCollection(TreeNodeAdv owner)
{
_owner = owner;
}
protected override void ClearItems()
{
while (this.Count != 0)
this.RemoveAt(this.Count - 1);
}
protected override void InsertItem(int index, TreeNodeAdv item)
{
if (item == null)
throw new ArgumentNullException("item");
if (item.Parent != _owner)
{
if (item.Parent != null)
item.Parent.Nodes.Remove(item);
item._parent = _owner;
item._index = index;
for (int i = index; i < Count; i++)
this[i]._index++;
base.InsertItem(index, item);
}
if (_owner.Tree != null && _owner.Tree.Model == null)
{
_owner.Tree.SmartFullUpdate();
}
}
protected override void RemoveItem(int index)
{
TreeNodeAdv item = this[index];
item._parent = null;
item._index = -1;
for (int i = index + 1; i < Count; i++)
this[i]._index--;
base.RemoveItem(index);
if (_owner.Tree != null && _owner.Tree.Model == null)
{
_owner.Tree.UpdateSelection();
_owner.Tree.SmartFullUpdate();
}
}
protected override void SetItem(int index, TreeNodeAdv item)
{
if (item == null)
throw new ArgumentNullException("item");
RemoveAt(index);
InsertItem(index, item);
}
}
#endregion
#region Events
public event EventHandler<TreeViewAdvEventArgs> Collapsing;
internal void OnCollapsing()
{
if (Collapsing != null)
Collapsing(this, new TreeViewAdvEventArgs(this));
}
public event EventHandler<TreeViewAdvEventArgs> Collapsed;
internal void OnCollapsed()
{
if (Collapsed != null)
Collapsed(this, new TreeViewAdvEventArgs(this));
}
public event EventHandler<TreeViewAdvEventArgs> Expanding;
internal void OnExpanding()
{
if (Expanding != null)
Expanding(this, new TreeViewAdvEventArgs(this));
}
public event EventHandler<TreeViewAdvEventArgs> Expanded;
internal void OnExpanded()
{
if (Expanded != null)
Expanded(this, new TreeViewAdvEventArgs(this));
}
#endregion
#region Properties
private TreeViewAdv _tree;
public TreeViewAdv Tree
{
get { return _tree; }
}
private int _row;
public int Row
{
get { return _row; }
internal set { _row = value; }
}
private int _index = -1;
public int Index
{
get
{
return _index;
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
if (Tree.IsMyNode(this))
{
//_tree.OnSelectionChanging
if (value)
{
if (!_tree.Selection.Contains(this))
_tree.Selection.Add(this);
if (_tree.Selection.Count == 1)
_tree.CurrentNode = this;
}
else
_tree.Selection.Remove(this);
_tree.UpdateView();
_tree.OnSelectionChanged();
}
_isSelected = value;
}
}
}
/// <summary>
/// Returns true if all parent nodes of this node are expanded.
/// </summary>
internal bool IsVisible
{
get
{
TreeNodeAdv node = _parent;
while (node != null)
{
if (!node.IsExpanded)
return false;
node = node.Parent;
}
return true;
}
}
private bool _isLeaf;
public bool IsLeaf
{
get { return _isLeaf; }
internal set { _isLeaf = value; }
}
private bool _isExpandedOnce;
public bool IsExpandedOnce
{
get { return _isExpandedOnce; }
internal set { _isExpandedOnce = value; }
}
private bool _isExpanded;
public bool IsExpanded
{
get { return _isExpanded; }
set
{
if (value)
Expand();
else
Collapse();
}
}
internal void AssignIsExpanded(bool value)
{
_isExpanded = value;
}
private TreeNodeAdv _parent;
public TreeNodeAdv Parent
{
get { return _parent; }
}
public int Level
{
get
{
if (_parent == null)
return 0;
else
return _parent.Level + 1;
}
}
public TreeNodeAdv PreviousNode
{
get
{
if (_parent != null)
{
int index = Index;
if (index > 0)
return _parent.Nodes[index - 1];
}
return null;
}
}
public TreeNodeAdv NextNode
{
get
{
if (_parent != null)
{
int index = Index;
if (index < _parent.Nodes.Count - 1)
return _parent.Nodes[index + 1];
}
return null;
}
}
internal TreeNodeAdv BottomNode
{
get
{
TreeNodeAdv parent = this.Parent;
if (parent != null)
{
if (parent.NextNode != null)
return parent.NextNode;
else
return parent.BottomNode;
}
return null;
}
}
internal TreeNodeAdv NextVisibleNode
{
get
{
if (IsExpanded && Nodes.Count > 0)
return Nodes[0];
else
{
TreeNodeAdv nn = NextNode;
if (nn != null)
return nn;
else
return BottomNode;
}
}
}
public bool CanExpand
{
get
{
return (Nodes.Count > 0 || (!IsExpandedOnce && !IsLeaf));
}
}
private object _tag;
public object Tag
{
get { return _tag; }
}
private Collection<TreeNodeAdv> _nodes;
internal Collection<TreeNodeAdv> Nodes
{
get { return _nodes; }
}
private ReadOnlyCollection<TreeNodeAdv> _children;
public ReadOnlyCollection<TreeNodeAdv> Children
{
get
{
return _children;
}
}
private int? _rightBounds;
internal int? RightBounds
{
get { return _rightBounds; }
set { _rightBounds = value; }
}
private int? _height;
internal int? Height
{
get { return _height; }
set { _height = value; }
}
private bool _isExpandingNow;
internal bool IsExpandingNow
{
get { return _isExpandingNow; }
set { _isExpandingNow = value; }
}
private bool _autoExpandOnStructureChanged = true;
public bool AutoExpandOnStructureChanged
{
get { return _autoExpandOnStructureChanged; }
set { _autoExpandOnStructureChanged = value; }
}
#endregion
public TreeNodeAdv(object tag)
: this(null, tag)
{
}
internal TreeNodeAdv(TreeViewAdv tree, object tag)
{
_row = -1;
_tree = tree;
_nodes = new NodeCollection(this);
_children = new ReadOnlyCollection<TreeNodeAdv>(_nodes);
_tag = tag;
}
public override string ToString()
{
if (Tag != null)
return Tag.ToString();
else
return base.ToString();
}
public void Collapse()
{
if (_isExpanded)
Collapse(true);
}
public void CollapseAll()
{
Collapse(false);
}
public void Collapse(bool ignoreChildren)
{
SetIsExpanded(false, ignoreChildren);
}
public void Expand()
{
if (!_isExpanded)
Expand(true);
}
public void ExpandAll()
{
Expand(false);
}
public void Expand(bool ignoreChildren)
{
SetIsExpanded(true, ignoreChildren);
}
private void SetIsExpanded(bool value, bool ignoreChildren)
{
if (Tree == null)
_isExpanded = value;
else
Tree.SetIsExpanded(this, value, ignoreChildren);
}
#region ISerializable Members
private TreeNodeAdv(SerializationInfo info, StreamingContext context)
: this(null, null)
{
int nodesCount = 0;
nodesCount = info.GetInt32("NodesCount");
_isExpanded = info.GetBoolean("IsExpanded");
_tag = info.GetValue("Tag", typeof(object));
for (int i = 0; i < nodesCount; i++)
{
TreeNodeAdv child = (TreeNodeAdv)info.GetValue("Child" + i, typeof(TreeNodeAdv));
Nodes.Add(child);
}
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("IsExpanded", IsExpanded);
info.AddValue("NodesCount", Nodes.Count);
if ((Tag != null) && Tag.GetType().IsSerializable)
info.AddValue("Tag", Tag, Tag.GetType());
for (int i = 0; i < Nodes.Count; i++)
info.AddValue("Child" + i, Nodes[i], typeof(TreeNodeAdv));
}
#endregion
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public class TreeNodeAdvMouseEventArgs : MouseEventArgs
{
private TreeNodeAdv _node;
public TreeNodeAdv Node
{
get { return _node; }
internal set { _node = value; }
}
private NodeControl _control;
public NodeControl Control
{
get { return _control; }
internal set { _control = value; }
}
private Point _viewLocation;
public Point ViewLocation
{
get { return _viewLocation; }
internal set { _viewLocation = value; }
}
private Keys _modifierKeys;
public Keys ModifierKeys
{
get { return _modifierKeys; }
internal set { _modifierKeys = value; }
}
private bool _handled;
public bool Handled
{
get { return _handled; }
set { _handled = value; }
}
private Rectangle _controlBounds;
public Rectangle ControlBounds
{
get { return _controlBounds; }
internal set { _controlBounds = value; }
}
public TreeNodeAdvMouseEventArgs(MouseEventArgs args)
: base(args.Button, args.Clicks, args.X, args.Y, args.Delta)
{
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Text;
using System.Collections.ObjectModel;
namespace Aga.Controls.Tree
{
public class TreePath
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
public static readonly TreePath Empty = new TreePath();
private object[] _path;
public object[] FullPath
{
get { return _path; }
}
public object LastNode
{
get
{
if (_path.Length > 0)
return _path[_path.Length - 1];
else
return null;
}
}
public object FirstNode
{
get
{
if (_path.Length > 0)
return _path[0];
else
return null;
}
}
public TreePath()
{
_path = new object[0];
}
public TreePath(object node)
{
_path = new object[] { node };
}
public TreePath(object[] path)
{
_path = path;
}
public TreePath(TreePath parent, object node)
{
_path = new object[parent.FullPath.Length + 1];
for (int i = 0; i < _path.Length - 1; i++)
_path[i] = parent.FullPath[i];
_path[_path.Length - 1] = node;
}
public bool IsEmpty()
{
return (_path.Length == 0);
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public class TreePathEventArgs : EventArgs
{
private TreePath _path;
public TreePath Path
{
get { return _path; }
}
public TreePathEventArgs()
{
_path = new TreePath();
}
public TreePathEventArgs(TreePath path)
{
if (path == null)
throw new ArgumentNullException();
_path = path;
}
}
}

View File

@@ -0,0 +1,69 @@
using System.Windows.Forms;
namespace Aga.Controls.Tree
{
partial class TreeViewAdv
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
if (_dragBitmap != null) _dragBitmap.Dispose();
if (_dragTimer != null) _dragTimer.Dispose();
if (_linePen != null) _linePen.Dispose();
if (_markPen != null) _markPen.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this._vScrollBar = new System.Windows.Forms.VScrollBar();
this._hScrollBar = new System.Windows.Forms.HScrollBar();
this._errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
((System.ComponentModel.ISupportInitialize)(this._errorProvider)).BeginInit();
this.SuspendLayout();
//
// _vScrollBar
//
this._vScrollBar.LargeChange = 1;
this._vScrollBar.Location = new System.Drawing.Point(0, 0);
this._vScrollBar.Maximum = 0;
this._vScrollBar.Name = "_vScrollBar";
this._vScrollBar.Size = new System.Drawing.Size(13, 80);
this._vScrollBar.TabIndex = 1;
this._vScrollBar.ValueChanged += new System.EventHandler(this._vScrollBar_ValueChanged);
this._vScrollBar.Scroll += new System.Windows.Forms.ScrollEventHandler(this._vScrollBar_Scroll);
//
// _hScrollBar
//
this._hScrollBar.LargeChange = 1;
this._hScrollBar.Location = new System.Drawing.Point(0, 0);
this._hScrollBar.Maximum = 0;
this._hScrollBar.Name = "_hScrollBar";
this._hScrollBar.Size = new System.Drawing.Size(80, 13);
this._hScrollBar.TabIndex = 2;
this._hScrollBar.ValueChanged += new System.EventHandler(this._hScrollBar_ValueChanged);
this._hScrollBar.Scroll += new System.Windows.Forms.ScrollEventHandler(this._hScrollBar_Scroll);
//
// TreeViewAdv
//
this.BackColor = System.Drawing.SystemColors.Window;
this.Controls.Add(this._vScrollBar);
this.Controls.Add(this._hScrollBar);
((System.ComponentModel.ISupportInitialize)(this._errorProvider)).EndInit();
this.ResumeLayout(false);
}
#endregion
private VScrollBar _vScrollBar;
private HScrollBar _hScrollBar;
private ErrorProvider _errorProvider;
}
}

View File

@@ -0,0 +1,310 @@
using System;
using System.Drawing;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public partial class TreeViewAdv
{
public void AutoSizeColumn(TreeColumn column)
{
if (!Columns.Contains(column))
throw new ArgumentException("column");
DrawContext context = new DrawContext();
context.Graphics = Graphics.FromImage(new Bitmap(1, 1));
context.Font = this.Font;
int res = 0;
for (int row = 0; row < RowCount; row++)
{
if (row < RowMap.Count)
{
int w = 0;
TreeNodeAdv node = RowMap[row];
foreach (NodeControl nc in NodeControls)
{
if (nc.ParentColumn == column)
w += nc.GetActualSize(node, _measureContext).Width;
}
res = Math.Max(res, w);
}
}
if (res > 0)
column.Width = res;
}
private void CreatePens()
{
CreateLinePen();
CreateMarkPen();
}
private void CreateMarkPen()
{
GraphicsPath path = new GraphicsPath();
path.AddLines(new Point[] { new Point(0, 0), new Point(1, 1), new Point(-1, 1), new Point(0, 0) });
CustomLineCap cap = new CustomLineCap(null, path);
cap.WidthScale = 1.0f;
_markPen = new Pen(_dragDropMarkColor, _dragDropMarkWidth);
_markPen.CustomStartCap = cap;
_markPen.CustomEndCap = cap;
}
private void CreateLinePen()
{
_linePen = new Pen(_lineColor);
_linePen.DashStyle = DashStyle.Dot;
}
protected override void OnPaint(PaintEventArgs e)
{
BeginPerformanceCount();
PerformanceAnalyzer.Start("OnPaint");
DrawContext context = new DrawContext();
context.Graphics = e.Graphics;
context.Font = this.Font;
context.Enabled = Enabled;
int y = 0;
int gridHeight = 0;
if (UseColumns)
{
DrawColumnHeaders(e.Graphics);
y += ColumnHeaderHeight;
if (Columns.Count == 0 || e.ClipRectangle.Height <= y)
return;
}
int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y;
y -= firstRowY;
e.Graphics.ResetTransform();
e.Graphics.TranslateTransform(-OffsetX, y);
Rectangle displayRect = DisplayRectangle;
for (int row = FirstVisibleRow; row < RowCount; row++)
{
Rectangle rowRect = _rowLayout.GetRowBounds(row);
gridHeight += rowRect.Height;
if (rowRect.Y + y > displayRect.Bottom)
break;
else
DrawRow(e, ref context, row, rowRect);
}
if ((GridLineStyle & GridLineStyle.Vertical) == GridLineStyle.Vertical && UseColumns)
DrawVerticalGridLines(e.Graphics, firstRowY);
if (_dropPosition.Node != null && DragMode && HighlightDropPosition)
DrawDropMark(e.Graphics);
e.Graphics.ResetTransform();
DrawScrollBarsBox(e.Graphics);
if (DragMode && _dragBitmap != null)
e.Graphics.DrawImage(_dragBitmap, PointToClient(MousePosition));
PerformanceAnalyzer.Finish("OnPaint");
EndPerformanceCount(e);
}
private void DrawRow(PaintEventArgs e, ref DrawContext context, int row, Rectangle rowRect)
{
TreeNodeAdv node = RowMap[row];
context.DrawSelection = DrawSelectionMode.None;
context.CurrentEditorOwner = CurrentEditorOwner;
if (DragMode)
{
if ((_dropPosition.Node == node) && _dropPosition.Position == NodePosition.Inside && HighlightDropPosition)
context.DrawSelection = DrawSelectionMode.Active;
}
else
{
if (node.IsSelected && Focused)
context.DrawSelection = DrawSelectionMode.Active;
else if (node.IsSelected && !Focused && !HideSelection)
context.DrawSelection = DrawSelectionMode.Inactive;
}
context.DrawFocus = Focused && CurrentNode == node;
OnRowDraw(e, node, context, row, rowRect);
if ((GridLineStyle & GridLineStyle.Horizontal) == GridLineStyle.Horizontal) {
e.Graphics.DrawLine(CustomHorizontalLinePen, 0, rowRect.Bottom, e.Graphics.ClipBounds.Right, rowRect.Bottom);
}
if (FullRowSelect)
{
context.DrawFocus = false;
if (context.DrawSelection == DrawSelectionMode.Active || context.DrawSelection == DrawSelectionMode.Inactive)
{
Rectangle focusRect = new Rectangle(OffsetX, rowRect.Y, ClientRectangle.Width, rowRect.Height);
if (context.DrawSelection == DrawSelectionMode.Active)
{
e.Graphics.FillRectangle(CustomSelectedRowBrush, focusRect);
context.DrawSelection = DrawSelectionMode.FullRowSelect;
}
else
{
e.Graphics.FillRectangle(CustomSelectedRowBrush, focusRect);
context.DrawSelection = DrawSelectionMode.None;
}
}
}
if (ShowLines)
DrawLines(e.Graphics, node, rowRect);
DrawNode(node, context);
}
private void DrawVerticalGridLines(Graphics gr, int y)
{
int x = 0;
foreach (TreeColumn c in Columns)
{
if (c.IsVisible)
{
x += c.Width;
gr.DrawLine(SystemPens.InactiveBorder, x - 1, y, x - 1, gr.ClipBounds.Bottom);
}
}
}
private void DrawColumnHeaders(Graphics gr)
{
PerformanceAnalyzer.Start("DrawColumnHeaders");
ReorderColumnState reorder = Input as ReorderColumnState;
int x = 0;
TreeColumn.DrawBackground(gr, new Rectangle(0, 0, ClientRectangle.Width + 2, ColumnHeaderHeight - 1), false, false);
gr.TranslateTransform(-OffsetX, 0);
foreach (TreeColumn c in Columns)
{
if (c.IsVisible)
{
if (x >= OffsetX && x - OffsetX < this.Bounds.Width)// skip invisible columns
{
Rectangle rect = new Rectangle(x, 0, c.Width, ColumnHeaderHeight - 1);
gr.SetClip(rect);
bool pressed = ((Input is ClickColumnState || reorder != null) && ((Input as ColumnState).Column == c));
c.Draw(gr, rect, Font, pressed, _hotColumn == c);
gr.ResetClip();
if (reorder != null && reorder.DropColumn == c)
TreeColumn.DrawDropMark(gr, rect);
}
x += c.Width;
}
}
if (reorder != null)
{
if (reorder.DropColumn == null)
TreeColumn.DrawDropMark(gr, new Rectangle(x, 0, 0, ColumnHeaderHeight));
gr.DrawImage(reorder.GhostImage, new Point(reorder.Location.X + + reorder.DragOffset, reorder.Location.Y));
}
PerformanceAnalyzer.Finish("DrawColumnHeaders");
}
public void DrawNode(TreeNodeAdv node, DrawContext context)
{
foreach (NodeControlInfo item in GetNodeControls(node))
{
if (item.Bounds.Right >= OffsetX && item.Bounds.X - OffsetX < this.Bounds.Width)// skip invisible nodes
{
context.Bounds = item.Bounds;
context.Graphics.SetClip(context.Bounds);
item.Control.Draw(node, context);
context.Graphics.ResetClip();
}
}
}
private void DrawScrollBarsBox(Graphics gr)
{
Rectangle r1 = DisplayRectangle;
Rectangle r2 = ClientRectangle;
gr.FillRectangle(SystemBrushes.Control,
new Rectangle(r1.Right, r1.Bottom, r2.Width - r1.Width, r2.Height - r1.Height));
}
private void DrawDropMark(Graphics gr)
{
if (_dropPosition.Position == NodePosition.Inside)
return;
Rectangle rect = GetNodeBounds(_dropPosition.Node);
int right = DisplayRectangle.Right - LeftMargin + OffsetX;
int y = rect.Y;
if (_dropPosition.Position == NodePosition.After)
y = rect.Bottom;
gr.DrawLine(_markPen, rect.X, y, right, y);
}
private void DrawLines(Graphics gr, TreeNodeAdv node, Rectangle rowRect)
{
if (UseColumns && Columns.Count > 0)
gr.SetClip(new Rectangle(0, rowRect.Y, Columns[0].Width, rowRect.Bottom));
TreeNodeAdv curNode = node;
while (curNode != _root && curNode != null)
{
int level = curNode.Level;
int scaledIndent = node.Tree.GetScaledSize(_indent, false);
int x = (level - 1) * scaledIndent + NodePlusMinus.ImageSize / 2 + LeftMargin;
int width = node.Tree.GetScaledSize(NodePlusMinus.Width - NodePlusMinus.ImageSize / 2, false);
int y = rowRect.Y;
int y2 = y + rowRect.Height;
if (curNode == node)
{
int midy = y + rowRect.Height / 2;
gr.DrawLine(_linePen, x, midy, x + width, midy);
if (curNode.NextNode == null)
y2 = y + rowRect.Height / 2;
}
if (node.Row == 0)
y = rowRect.Height / 2;
if (curNode.NextNode != null || curNode == node)
gr.DrawLine(_linePen, x, y, x, y2);
curNode = curNode.Parent;
}
gr.ResetClip();
}
#region Performance
private double _totalTime;
private int _paintCount;
[Conditional("PERF_TEST")]
private void BeginPerformanceCount()
{
_paintCount++;
TimeCounter.Start();
}
[Conditional("PERF_TEST")]
private void EndPerformanceCount(PaintEventArgs e)
{
double time = TimeCounter.Finish();
_totalTime += time;
string debugText = string.Format("FPS {0:0.0}; Avg. FPS {1:0.0}",
1 / time, 1 / (_totalTime / _paintCount));
e.Graphics.FillRectangle(Brushes.White, new Rectangle(DisplayRectangle.Width - 150, DisplayRectangle.Height - 20, 150, 20));
e.Graphics.DrawString(debugText, Control.DefaultFont, Brushes.Gray,
new PointF(DisplayRectangle.Width - 150, DisplayRectangle.Height - 20));
}
#endregion
}
}

View File

@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Aga.Controls.Tree.NodeControls;
using System.Drawing;
namespace Aga.Controls.Tree
{
partial class TreeViewAdv
{
private TreeNodeAdv _editingNode;
public EditableControl CurrentEditorOwner { get; private set; }
public Control CurrentEditor { get; private set; }
public void HideEditor()
{
if (CurrentEditorOwner != null)
CurrentEditorOwner.EndEdit(false);
}
internal void DisplayEditor(Control editor, EditableControl owner)
{
if (editor == null || owner == null || CurrentNode == null)
throw new ArgumentNullException();
HideEditor(false);
CurrentEditor = editor;
CurrentEditorOwner = owner;
_editingNode = CurrentNode;
editor.Validating += EditorValidating;
UpdateEditorBounds();
UpdateView();
editor.Parent = this;
editor.Focus();
owner.UpdateEditor(editor);
}
internal bool HideEditor(bool applyChanges)
{
if (CurrentEditor != null)
{
if (applyChanges)
{
if (!ApplyChanges())
return false;
}
//Check once more if editor was closed in ApplyChanges
if (CurrentEditor != null)
{
CurrentEditor.Validating -= EditorValidating;
CurrentEditorOwner.DoDisposeEditor(CurrentEditor);
CurrentEditor.Parent = null;
CurrentEditor.Dispose();
CurrentEditor = null;
CurrentEditorOwner = null;
_editingNode = null;
}
}
return true;
}
private bool ApplyChanges()
{
try
{
CurrentEditorOwner.ApplyChanges(_editingNode, CurrentEditor);
_errorProvider.Clear();
return true;
}
catch (ArgumentException ex)
{
_errorProvider.SetError(CurrentEditor, ex.Message);
/*CurrentEditor.Validating -= EditorValidating;
MessageBox.Show(this, ex.Message, "Value is not valid", MessageBoxButtons.OK, MessageBoxIcon.Warning);
CurrentEditor.Focus();
CurrentEditor.Validating += EditorValidating;*/
return false;
}
}
void EditorValidating(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = !ApplyChanges();
}
public void UpdateEditorBounds()
{
if (CurrentEditor != null)
{
EditorContext context = new EditorContext();
context.Owner = CurrentEditorOwner;
context.CurrentNode = CurrentNode;
context.Editor = CurrentEditor;
context.DrawContext = _measureContext;
SetEditorBounds(context);
}
}
private void SetEditorBounds(EditorContext context)
{
foreach (NodeControlInfo info in GetNodeControls(context.CurrentNode))
{
if (context.Owner == info.Control && info.Control is EditableControl)
{
Point p = info.Bounds.Location;
p.X += info.Control.LeftMargin;
p.X -= OffsetX;
p.Y -= (_rowLayout.GetRowBounds(FirstVisibleRow).Y - ColumnHeaderHeight);
int width = DisplayRectangle.Width - p.X;
if (UseColumns && info.Control.ParentColumn != null && Columns.Contains(info.Control.ParentColumn))
{
Rectangle rect = GetColumnBounds(info.Control.ParentColumn.Index);
width = rect.Right - OffsetX - p.X;
}
context.Bounds = new Rectangle(p.X, p.Y, width, info.Bounds.Height);
((EditableControl)info.Control).SetEditorBounds(context);
return;
}
}
}
private Rectangle GetColumnBounds(int column)
{
int x = 0;
for (int i = 0; i < Columns.Count; i++)
{
if (Columns[i].IsVisible)
{
if (i < column)
x += Columns[i].Width;
else
return new Rectangle(x, 0, Columns[i].Width, 0);
}
}
return Rectangle.Empty;
}
}
}

View File

@@ -0,0 +1,558 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using Aga.Controls.Tree.NodeControls;
using System.Drawing.Imaging;
using System.Threading;
namespace Aga.Controls.Tree
{
public partial class TreeViewAdv
{
#region Keys
protected override bool IsInputChar(char charCode)
{
return true;
}
protected override bool IsInputKey(Keys keyData)
{
if (((keyData & Keys.Up) == Keys.Up)
|| ((keyData & Keys.Down) == Keys.Down)
|| ((keyData & Keys.Left) == Keys.Left)
|| ((keyData & Keys.Right) == Keys.Right))
return true;
else
return base.IsInputKey(keyData);
}
internal void ChangeInput()
{
if ((ModifierKeys & Keys.Shift) == Keys.Shift)
{
if (!(Input is InputWithShift))
Input = new InputWithShift(this);
}
else if ((ModifierKeys & Keys.Control) == Keys.Control)
{
if (!(Input is InputWithControl))
Input = new InputWithControl(this);
}
else
{
if (!(Input.GetType() == typeof(NormalInputState)))
Input = new NormalInputState(this);
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (!e.Handled)
{
if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey)
ChangeInput();
Input.KeyDown(e);
if (!e.Handled)
{
foreach (NodeControlInfo item in GetNodeControls(CurrentNode))
{
item.Control.KeyDown(e);
if (e.Handled)
break;
}
}
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if (!e.Handled)
{
if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey)
ChangeInput();
if (!e.Handled)
{
foreach (NodeControlInfo item in GetNodeControls(CurrentNode))
{
item.Control.KeyUp(e);
if (e.Handled)
return;
}
}
}
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (!e.Handled)
_search.Search(e.KeyChar);
}
#endregion
#region Mouse
private TreeNodeAdvMouseEventArgs CreateMouseArgs(MouseEventArgs e)
{
TreeNodeAdvMouseEventArgs args = new TreeNodeAdvMouseEventArgs(e);
args.ViewLocation = new Point(e.X + OffsetX,
e.Y + _rowLayout.GetRowBounds(FirstVisibleRow).Y - ColumnHeaderHeight);
args.ModifierKeys = ModifierKeys;
args.Node = GetNodeAt(e.Location);
NodeControlInfo info = GetNodeControlInfoAt(args.Node, e.Location);
args.ControlBounds = info.Bounds;
args.Control = info.Control;
return args;
}
protected override void OnMouseWheel(MouseEventArgs e)
{
_search.EndSearch();
if (SystemInformation.MouseWheelScrollLines > 0)
{
int lines = e.Delta / 120 * SystemInformation.MouseWheelScrollLines;
int newValue = _vScrollBar.Value - lines;
newValue = Math.Min(_vScrollBar.Maximum - _vScrollBar.LargeChange + 1, newValue);
newValue = Math.Min(_vScrollBar.Maximum, newValue);
_vScrollBar.Value = Math.Max(_vScrollBar.Minimum, newValue);
}
base.OnMouseWheel(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (CurrentEditorOwner != null)
{
CurrentEditorOwner.EndEdit(true);
return;
}
if (!Focused)
Focus();
_search.EndSearch();
if (e.Button == MouseButtons.Left)
{
TreeColumn c;
c = GetColumnDividerAt(e.Location);
if (c != null)
{
Input = new ResizeColumnState(this, c, e.Location);
return;
}
c = GetColumnAt(e.Location);
if (c != null)
{
Input = new ClickColumnState(this, c, e.Location);
UpdateView();
return;
}
}
ChangeInput();
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
if (args.Node != null && args.Control != null)
args.Control.MouseDown(args);
if (!args.Handled)
Input.MouseDown(args);
base.OnMouseDown(e);
}
protected override void OnMouseClick(MouseEventArgs e)
{
//TODO: Disable when click on plusminus icon
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
if (args.Node != null)
OnNodeMouseClick(args);
base.OnMouseClick(e);
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
if (args.Node != null && args.Control != null)
args.Control.MouseDoubleClick(args);
if (!args.Handled)
{
if (args.Node != null)
OnNodeMouseDoubleClick(args);
else
Input.MouseDoubleClick(args);
if (!args.Handled)
{
if (args.Node != null && args.Button == MouseButtons.Left)
args.Node.IsExpanded = !args.Node.IsExpanded;
}
}
base.OnMouseDoubleClick(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
if (Input is ResizeColumnState)
Input.MouseUp(args);
else
{
if (args.Node != null && args.Control != null)
args.Control.MouseUp(args);
if (!args.Handled)
Input.MouseUp(args);
base.OnMouseUp(e);
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (Input.MouseMove(e))
return;
base.OnMouseMove(e);
SetCursor(e);
UpdateToolTip(e);
if (ItemDragMode && Dist(e.Location, ItemDragStart) > ItemDragSensivity
&& CurrentNode != null && CurrentNode.IsSelected)
{
ItemDragMode = false;
_toolTip.Active = false;
OnItemDrag(e.Button, Selection.ToArray());
}
}
protected override void OnMouseLeave(EventArgs e)
{
_hotColumn = null;
UpdateHeaders();
base.OnMouseLeave(e);
}
private void SetCursor(MouseEventArgs e)
{
TreeColumn col;
col = GetColumnDividerAt(e.Location);
if (col == null)
_innerCursor = null;
else
{
if (col.Width == 0)
_innerCursor = ResourceHelper.DVSplitCursor;
else
_innerCursor = Cursors.VSplit;
}
col = GetColumnAt(e.Location);
if (col != _hotColumn)
{
_hotColumn = col;
UpdateHeaders();
}
}
internal TreeColumn GetColumnAt(Point p)
{
if (p.Y > ColumnHeaderHeight)
return null;
int x = -OffsetX;
foreach (TreeColumn col in Columns)
{
if (col.IsVisible)
{
Rectangle rect = new Rectangle(x, 0, col.Width, ColumnHeaderHeight);
x += col.Width;
if (rect.Contains(p))
return col;
}
}
return null;
}
internal int GetColumnX(TreeColumn column)
{
int x = -OffsetX;
foreach (TreeColumn col in Columns)
{
if (col.IsVisible)
{
if (column == col)
return x;
else
x += col.Width;
}
}
return x;
}
internal TreeColumn GetColumnDividerAt(Point p)
{
if (p.Y > ColumnHeaderHeight)
return null;
int x = -OffsetX;
TreeColumn prevCol = null;
Rectangle left, right;
foreach (TreeColumn col in Columns)
{
if (col.IsVisible)
{
if (col.Width > 0)
{
left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight);
right = new Rectangle(x + col.Width - (DividerWidth / 2), 0, DividerWidth / 2, ColumnHeaderHeight);
if (left.Contains(p) && prevCol != null)
return prevCol;
else if (right.Contains(p))
return col;
}
prevCol = col;
x += col.Width;
}
}
left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight);
if (left.Contains(p) && prevCol != null)
return prevCol;
return null;
}
TreeColumn _tooltipColumn;
private void UpdateToolTip(MouseEventArgs e)
{
TreeColumn col = GetColumnAt(e.Location);
if (col != null)
{
if (col != _tooltipColumn)
SetTooltip(col.TooltipText);
}
else
DisplayNodesTooltip(e);
_tooltipColumn = col;
}
TreeNodeAdv _hotNode;
NodeControl _hotControl;
private void DisplayNodesTooltip(MouseEventArgs e)
{
if (ShowNodeToolTips)
{
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e);
if (args.Node != null && args.Control != null)
{
if (args.Node != _hotNode || args.Control != _hotControl)
SetTooltip(GetNodeToolTip(args));
}
else
_toolTip.SetToolTip(this, null);
_hotControl = args.Control;
_hotNode = args.Node;
}
else
_toolTip.SetToolTip(this, null);
}
private void SetTooltip(string text)
{
if (!String.IsNullOrEmpty(text))
{
_toolTip.Active = false;
_toolTip.SetToolTip(this, text);
_toolTip.Active = true;
}
else
_toolTip.SetToolTip(this, null);
}
private string GetNodeToolTip(TreeNodeAdvMouseEventArgs args)
{
string msg = args.Control.GetToolTip(args.Node);
BaseTextControl btc = args.Control as BaseTextControl;
if (btc != null && btc.DisplayHiddenContentInToolTip && String.IsNullOrEmpty(msg))
{
Size ms = btc.GetActualSize(args.Node, _measureContext);
if (ms.Width > args.ControlBounds.Size.Width || ms.Height > args.ControlBounds.Size.Height
|| args.ControlBounds.Right - OffsetX > DisplayRectangle.Width)
msg = btc.GetLabel(args.Node);
}
if (String.IsNullOrEmpty(msg) && DefaultToolTipProvider != null)
msg = DefaultToolTipProvider.GetToolTip(args.Node, args.Control);
return msg;
}
#endregion
#region DragDrop
private bool _dragAutoScrollFlag = false;
private Bitmap _dragBitmap = null;
private System.Threading.Timer _dragTimer;
private void StartDragTimer()
{
if (_dragTimer == null)
_dragTimer = new System.Threading.Timer(new TimerCallback(DragTimerTick), null, 0, 100);
}
private void StopDragTimer()
{
if (_dragTimer != null)
{
_dragTimer.Dispose();
_dragTimer = null;
}
}
private void SetDropPosition(Point pt)
{
TreeNodeAdv node = GetNodeAt(pt);
OnDropNodeValidating(pt, ref node);
_dropPosition.Node = node;
if (node != null)
{
Rectangle first = _rowLayout.GetRowBounds(FirstVisibleRow);
Rectangle bounds = _rowLayout.GetRowBounds(node.Row);
float pos = (pt.Y + first.Y - ColumnHeaderHeight - bounds.Y) / (float)bounds.Height;
if (pos < TopEdgeSensivity)
_dropPosition.Position = NodePosition.Before;
else if (pos > (1 - BottomEdgeSensivity))
_dropPosition.Position = NodePosition.After;
else
_dropPosition.Position = NodePosition.Inside;
}
}
private void DragTimerTick(object state)
{
_dragAutoScrollFlag = true;
}
private void DragAutoScroll()
{
_dragAutoScrollFlag = false;
Point pt = PointToClient(MousePosition);
if (pt.Y < 20 && _vScrollBar.Value > 0)
_vScrollBar.Value--;
else if (pt.Y > Height - 20 && _vScrollBar.Value <= _vScrollBar.Maximum - _vScrollBar.LargeChange)
_vScrollBar.Value++;
}
public void DoDragDropSelectedNodes(DragDropEffects allowedEffects)
{
if (SelectedNodes.Count > 0)
{
TreeNodeAdv[] nodes = new TreeNodeAdv[SelectedNodes.Count];
SelectedNodes.CopyTo(nodes, 0);
DoDragDrop(nodes, allowedEffects);
}
}
private void CreateDragBitmap(IDataObject data)
{
if (UseColumns || !DisplayDraggingNodes)
return;
TreeNodeAdv[] nodes = data.GetData(typeof(TreeNodeAdv[])) as TreeNodeAdv[];
if (nodes != null && nodes.Length > 0)
{
Rectangle rect = DisplayRectangle;
Bitmap bitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics gr = Graphics.FromImage(bitmap))
{
gr.Clear(BackColor);
DrawContext context = new DrawContext();
context.Graphics = gr;
context.Font = Font;
context.Enabled = true;
int y = 0;
int maxWidth = 0;
foreach (TreeNodeAdv node in nodes)
{
if (node.Tree == this)
{
int x = 0;
int height = _rowLayout.GetRowBounds(node.Row).Height;
foreach (NodeControl c in NodeControls)
{
Size s = c.GetActualSize(node, context);
if (!s.IsEmpty)
{
int width = s.Width;
rect = new Rectangle(x, y, width, height);
x += (width + 1);
context.Bounds = rect;
c.Draw(node, context);
}
}
y += height;
maxWidth = Math.Max(maxWidth, x);
}
}
if (maxWidth > 0 && y > 0)
{
_dragBitmap = new Bitmap(maxWidth, y, PixelFormat.Format32bppArgb);
using (Graphics tgr = Graphics.FromImage(_dragBitmap))
tgr.DrawImage(bitmap, Point.Empty);
BitmapHelper.SetAlphaChanelValue(_dragBitmap, 150);
}
else
_dragBitmap = null;
}
}
}
protected override void OnDragOver(DragEventArgs drgevent)
{
ItemDragMode = false;
Point pt = PointToClient(new Point(drgevent.X, drgevent.Y));
if (_dragAutoScrollFlag)
DragAutoScroll();
SetDropPosition(pt);
UpdateView();
base.OnDragOver(drgevent);
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
_search.EndSearch();
DragMode = true;
CreateDragBitmap(drgevent.Data);
base.OnDragEnter(drgevent);
}
protected override void OnDragLeave(EventArgs e)
{
DragMode = false;
UpdateView();
base.OnDragLeave(e);
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
DragMode = false;
UpdateView();
base.OnDragDrop(drgevent);
}
#endregion
}
}

View File

@@ -0,0 +1,727 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using Aga.Controls.Tree.NodeControls;
namespace Aga.Controls.Tree
{
public partial class TreeViewAdv
{
private Cursor _innerCursor = null;
public override Cursor Cursor
{
get
{
if (_innerCursor != null)
return _innerCursor;
else
return base.Cursor;
}
set
{
base.Cursor = value;
}
}
#region Internal Properties
private IRowLayout _rowLayout;
private bool _dragMode;
private bool DragMode
{
get { return _dragMode; }
set
{
_dragMode = value;
if (!value)
{
StopDragTimer();
if (_dragBitmap != null)
_dragBitmap.Dispose();
_dragBitmap = null;
}
else
StartDragTimer();
}
}
internal int ColumnHeaderHeight
{
get
{
if (UseColumns)
return _columnHeaderHeight;
else
return 0;
}
}
/// <summary>
/// returns all nodes, which parent is expanded
/// </summary>
private IEnumerable<TreeNodeAdv> VisibleNodes
{
get
{
TreeNodeAdv node = Root;
while (node != null)
{
node = node.NextVisibleNode;
if (node != null)
yield return node;
}
}
}
private bool _suspendSelectionEvent;
internal bool SuspendSelectionEvent
{
get { return _suspendSelectionEvent; }
set
{
if (value != _suspendSelectionEvent)
{
_suspendSelectionEvent = value;
if (!_suspendSelectionEvent && _fireSelectionEvent)
OnSelectionChanged();
}
}
}
private List<TreeNodeAdv> _rowMap;
internal List<TreeNodeAdv> RowMap
{
get { return _rowMap; }
}
private TreeNodeAdv _selectionStart;
internal TreeNodeAdv SelectionStart
{
get { return _selectionStart; }
set { _selectionStart = value; }
}
private InputState _input;
internal InputState Input
{
get { return _input; }
set
{
_input = value;
}
}
private bool _itemDragMode;
internal bool ItemDragMode
{
get { return _itemDragMode; }
set { _itemDragMode = value; }
}
private Point _itemDragStart;
internal Point ItemDragStart
{
get { return _itemDragStart; }
set { _itemDragStart = value; }
}
/// <summary>
/// Number of rows fits to the current page
/// </summary>
internal int CurrentPageSize
{
get
{
return _rowLayout.CurrentPageSize;
}
}
/// <summary>
/// Number of all visible nodes (which parent is expanded)
/// </summary>
internal int RowCount
{
get
{
return RowMap.Count;
}
}
private int _contentWidth = 0;
private int ContentWidth
{
get
{
return _contentWidth;
}
}
private int _firstVisibleRow;
internal int FirstVisibleRow
{
get { return _firstVisibleRow; }
set
{
HideEditor();
_firstVisibleRow = value;
UpdateView();
}
}
private int _offsetX;
public int OffsetX
{
get { return _offsetX; }
private set
{
HideEditor();
_offsetX = value;
UpdateView();
}
}
public override Rectangle DisplayRectangle
{
get
{
Rectangle r = ClientRectangle;
//r.Y += ColumnHeaderHeight;
//r.Height -= ColumnHeaderHeight;
int w = _vScrollBar.Visible ? _vScrollBar.Width : 0;
int h = _hScrollBar.Visible ? _hScrollBar.Height : 0;
return new Rectangle(r.X, r.Y, r.Width - w, r.Height - h);
}
}
private List<TreeNodeAdv> _selection;
internal List<TreeNodeAdv> Selection
{
get { return _selection; }
}
#endregion
#region Public Properties
#region DesignTime
private bool _shiftFirstNode;
[DefaultValue(false), Category("Behavior")]
public bool ShiftFirstNode
{
get { return _shiftFirstNode; }
set { _shiftFirstNode = value; }
}
private bool _displayDraggingNodes;
[DefaultValue(false), Category("Behavior")]
public bool DisplayDraggingNodes
{
get { return _displayDraggingNodes; }
set { _displayDraggingNodes = value; }
}
private bool _fullRowSelect;
[DefaultValue(false), Category("Behavior")]
public bool FullRowSelect
{
get { return _fullRowSelect; }
set
{
_fullRowSelect = value;
UpdateView();
}
}
private bool _useColumns;
[DefaultValue(false), Category("Behavior")]
public bool UseColumns
{
get { return _useColumns; }
set
{
_useColumns = value;
FullUpdate();
}
}
private bool _allowColumnReorder;
[DefaultValue(false), Category("Behavior")]
public bool AllowColumnReorder
{
get { return _allowColumnReorder; }
set { _allowColumnReorder = value; }
}
private bool _showLines = true;
[DefaultValue(true), Category("Behavior")]
public bool ShowLines
{
get { return _showLines; }
set
{
_showLines = value;
UpdateView();
}
}
private bool _showPlusMinus = true;
[DefaultValue(true), Category("Behavior")]
public bool ShowPlusMinus
{
get { return _showPlusMinus; }
set
{
_showPlusMinus = value;
FullUpdate();
}
}
private bool _showNodeToolTips = false;
[DefaultValue(false), Category("Behavior")]
public bool ShowNodeToolTips
{
get { return _showNodeToolTips; }
set { _showNodeToolTips = value; }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), DefaultValue(true), Category("Behavior"), Obsolete("No longer used")]
public bool KeepNodesExpanded
{
get { return true; }
set {}
}
private ITreeModel _model;
/// <Summary>
/// The model associated with this <see cref="TreeViewAdv"/>.
/// </Summary>
/// <seealso cref="ITreeModel"/>
/// <seealso cref="TreeModel"/>
[Browsable(false)]
public ITreeModel Model
{
get { return _model; }
set
{
if (_model != value)
{
AbortBackgroundExpandingThreads();
if (_model != null)
UnbindModelEvents();
_model = value;
CreateNodes();
FullUpdate();
if (_model != null)
BindModelEvents();
}
}
}
private static Font _font = SystemFonts.MessageBoxFont;
/// <summary>
/// The font to render <see cref="TreeViewAdv"/> content in.
/// </summary>
[Category("Appearance"), Description("The font to render TreeViewAdv content in.")]
public override Font Font
{
get
{
return (base.Font);
}
set
{
if (value == null)
base.Font = _font;
else
{
if (value == DefaultFont)
base.Font = _font;
else
base.Font = value;
}
}
}
public override void ResetFont()
{
Font = null;
}
private bool ShouldSerializeFont()
{
return (!Font.Equals(_font));
}
// End font property
private BorderStyle _borderStyle = BorderStyle.Fixed3D;
[DefaultValue(BorderStyle.Fixed3D), Category("Appearance")]
public BorderStyle BorderStyle
{
get
{
return this._borderStyle;
}
set
{
if (_borderStyle != value)
{
_borderStyle = value;
base.UpdateStyles();
}
}
}
private bool _autoRowHeight = false;
/// <summary>
/// Set to true to expand each row's height to fit the text of it's largest column.
/// </summary>
[DefaultValue(false), Category("Appearance"), Description("Expand each row's height to fit the text of it's largest column.")]
public bool AutoRowHeight
{
get
{
return _autoRowHeight;
}
set
{
_autoRowHeight = value;
if (value)
_rowLayout = new AutoRowHeightLayout(this, RowHeight);
else
_rowLayout = new FixedRowHeightLayout(this, RowHeight);
FullUpdate();
}
}
private GridLineStyle _gridLineStyle = GridLineStyle.None;
[DefaultValue(GridLineStyle.None), Category("Appearance")]
public GridLineStyle GridLineStyle
{
get
{
return _gridLineStyle;
}
set
{
if (value != _gridLineStyle)
{
_gridLineStyle = value;
UpdateView();
OnGridLineStyleChanged();
}
}
}
private int _rowHeight = 16;
[DefaultValue(16), Category("Appearance")]
public int RowHeight
{
get
{
return _rowHeight;
}
set
{
if (value <= 0)
throw new ArgumentOutOfRangeException("value");
_rowHeight = value;
_rowLayout.PreferredRowHeight = value;
FullUpdate();
}
}
private TreeSelectionMode _selectionMode = TreeSelectionMode.Single;
[DefaultValue(TreeSelectionMode.Single), Category("Behavior")]
public TreeSelectionMode SelectionMode
{
get { return _selectionMode; }
set { _selectionMode = value; }
}
private bool _hideSelection;
[DefaultValue(false), Category("Behavior")]
public bool HideSelection
{
get { return _hideSelection; }
set
{
_hideSelection = value;
UpdateView();
}
}
private float _topEdgeSensivity = 0.3f;
[DefaultValue(0.3f), Category("Behavior")]
public float TopEdgeSensivity
{
get { return _topEdgeSensivity; }
set
{
if (value < 0 || value > 1)
throw new ArgumentOutOfRangeException();
_topEdgeSensivity = value;
}
}
private float _bottomEdgeSensivity = 0.3f;
[DefaultValue(0.3f), Category("Behavior")]
public float BottomEdgeSensivity
{
get { return _bottomEdgeSensivity; }
set
{
if (value < 0 || value > 1)
throw new ArgumentOutOfRangeException("value should be from 0 to 1");
_bottomEdgeSensivity = value;
}
}
private bool _loadOnDemand;
[DefaultValue(false), Category("Behavior")]
public bool LoadOnDemand
{
get { return _loadOnDemand; }
set { _loadOnDemand = value; }
}
private bool _unloadCollapsedOnReload = false;
[DefaultValue(false), Category("Behavior")]
public bool UnloadCollapsedOnReload
{
get { return _unloadCollapsedOnReload; }
set { _unloadCollapsedOnReload = value; }
}
private int _indent = 19;
[DefaultValue(19), Category("Behavior")]
public int Indent
{
get { return _indent; }
set
{
_indent = value;
UpdateView();
}
}
private Color _lineColor = SystemColors.ControlDark;
[Category("Behavior")]
public Color LineColor
{
get { return _lineColor; }
set
{
_lineColor = value;
CreateLinePen();
UpdateView();
}
}
private Color _dragDropMarkColor = Color.Black;
[Category("Behavior")]
public Color DragDropMarkColor
{
get { return _dragDropMarkColor; }
set
{
_dragDropMarkColor = value;
CreateMarkPen();
}
}
private float _dragDropMarkWidth = 3.0f;
[DefaultValue(3.0f), Category("Behavior")]
public float DragDropMarkWidth
{
get { return _dragDropMarkWidth; }
set
{
_dragDropMarkWidth = value;
CreateMarkPen();
}
}
private bool _highlightDropPosition = true;
[DefaultValue(true), Category("Behavior")]
public bool HighlightDropPosition
{
get { return _highlightDropPosition; }
set { _highlightDropPosition = value; }
}
private TreeColumnCollection _columns;
[Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Collection<TreeColumn> Columns
{
get { return _columns; }
}
private NodeControlsCollection _controls;
[Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(NodeControlCollectionEditor), typeof(UITypeEditor))]
public Collection<NodeControl> NodeControls
{
get
{
return _controls;
}
}
private bool _asyncExpanding;
/// <summary>
/// When set to true, node contents will be read in background thread.
/// </summary>
[Category("Behavior"), DefaultValue(false), Description("Read children in a background thread when expanding.")]
public bool AsyncExpanding
{
get { return _asyncExpanding; }
set { _asyncExpanding = value; }
}
#endregion
#region RunTime
private IToolTipProvider _defaultToolTipProvider = null;
[Browsable(false)]
public IToolTipProvider DefaultToolTipProvider
{
get { return _defaultToolTipProvider; }
set { _defaultToolTipProvider = value; }
}
[Browsable(false)]
public IEnumerable<TreeNodeAdv> AllNodes
{
get
{
if (_root.Nodes.Count > 0)
{
TreeNodeAdv node = _root.Nodes[0];
while (node != null)
{
yield return node;
if (node.Nodes.Count > 0)
node = node.Nodes[0];
else if (node.NextNode != null)
node = node.NextNode;
else
node = node.BottomNode;
}
}
}
}
private DropPosition _dropPosition;
[Browsable(false)]
public DropPosition DropPosition
{
get { return _dropPosition; }
set { _dropPosition = value; }
}
private TreeNodeAdv _root;
[Browsable(false)]
public TreeNodeAdv Root
{
get { return _root; }
}
private ReadOnlyCollection<TreeNodeAdv> _readonlySelection;
[Browsable(false)]
public ReadOnlyCollection<TreeNodeAdv> SelectedNodes
{
get
{
return _readonlySelection;
}
}
[Browsable(false)]
public TreeNodeAdv SelectedNode
{
get
{
if (Selection.Count > 0)
{
if (CurrentNode != null && CurrentNode.IsSelected)
return CurrentNode;
else
return Selection[0];
}
else
return null;
}
set
{
if (SelectedNode == value)
return;
BeginUpdate();
try
{
if (value == null)
{
ClearSelectionInternal();
}
else
{
if (!IsMyNode(value))
throw new ArgumentException();
ClearSelectionInternal();
value.IsSelected = true;
CurrentNode = value;
EnsureVisible(value);
}
}
finally
{
EndUpdate();
}
}
}
private TreeNodeAdv _currentNode;
[Browsable(false)]
public TreeNodeAdv CurrentNode
{
get { return _currentNode; }
internal set { _currentNode = value; }
}
[Browsable(false)]
public int ItemCount
{
get { return RowMap.Count; }
}
/// <summary>
/// Indicates the distance the content is scrolled to the left
/// </summary>
[Browsable(false)]
public int HorizontalScrollPosition
{
get
{
if (_hScrollBar.Visible)
return _hScrollBar.Value;
else
return 0;
}
}
#endregion
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="_vScrollBar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>127, 17</value>
</metadata>
<metadata name="_hScrollBar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="_errorProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>236, 17</value>
</metadata>
<metadata name="$this.TrayLargeIcon" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
</root>

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public class TreeViewAdvCancelEventArgs : TreeViewAdvEventArgs
{
private bool _cancel;
public bool Cancel
{
get { return _cancel; }
set { _cancel = value; }
}
public TreeViewAdvCancelEventArgs(TreeNodeAdv node)
: base(node)
{
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Aga.Controls.Tree
{
public class TreeViewAdvEventArgs : EventArgs
{
private TreeNodeAdv _node;
public TreeNodeAdv Node
{
get { return _node; }
}
public TreeViewAdvEventArgs(TreeNodeAdv node)
{
_node = node;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace Aga.Controls.Tree
{
public class TreeViewRowDrawEventArgs: PaintEventArgs
{
TreeNodeAdv _node;
DrawContext _context;
int _row;
Rectangle _rowRect;
public TreeViewRowDrawEventArgs(Graphics graphics, Rectangle clipRectangle, TreeNodeAdv node, DrawContext context, int row, Rectangle rowRect)
: base(graphics, clipRectangle)
{
_node = node;
_context = context;
_row = row;
_rowRect = rowRect;
}
public TreeNodeAdv Node
{
get { return _node; }
}
public DrawContext Context
{
get { return _context; }
}
public int Row
{
get { return _row; }
}
public Rectangle RowRect
{
get { return _rowRect; }
}
}
}