Browse Source

ICSharpCode.TreeView: improve API for drag/drop/copy/paste of nodes.

newNR
Daniel Grunwald 12 years ago
parent
commit
f27a7426b2
  1. 35
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineNode.cs
  2. 17
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
  3. 10
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/SharpTreeNodeAdapter.cs
  4. 21
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichText.cs
  5. 19
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModel.cs
  6. 3
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RichTextWriter.cs
  7. 15
      src/Libraries/SharpTreeView/ICSharpCode.TreeView.Demo/FileNode.cs
  8. 44
      src/Libraries/SharpTreeView/ICSharpCode.TreeView.Demo/FileSystemNode.cs
  9. 36
      src/Libraries/SharpTreeView/ICSharpCode.TreeView.Demo/FolderNode.cs
  10. 106
      src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs
  11. 7
      src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNodeView.cs
  12. 78
      src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeView.cs
  13. 4
      src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeViewItem.cs

35
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlOutlineNode.cs

@ -36,22 +36,12 @@ namespace ICSharpCode.XamlBinding
public ITextAnchor EndMarker { get; set; } public ITextAnchor EndMarker { get; set; }
public ITextEditor Editor { get; set; } public ITextEditor Editor { get; set; }
public override bool CanDrag(SharpTreeNode[] nodes)
{
return false; //nodes.All(node => node.Parent != null);
}
public override bool CanDrop(DragEventArgs e, int index)
{
return false;
}
public string GetMarkupText() public string GetMarkupText()
{ {
return Editor.Document.GetText(Marker.Offset, EndMarker.Offset - Marker.Offset); return Editor.Document.GetText(Marker.Offset, EndMarker.Offset - Marker.Offset);
} }
public override IDataObject Copy(SharpTreeNode[] nodes) protected override IDataObject GetDataObject(SharpTreeNode[] nodes)
{ {
string[] data = nodes string[] data = nodes
.OfType<XamlOutlineNode>() .OfType<XamlOutlineNode>()
@ -63,11 +53,6 @@ namespace ICSharpCode.XamlBinding
return dataObject; return dataObject;
} }
public override bool CanDelete()
{
return Parent != null;
}
// public override void Drop(IDataObject data, int index, DropEffect finalEffect) // public override void Drop(IDataObject data, int index, DropEffect finalEffect)
// { // {
// try { // try {
@ -96,12 +81,24 @@ namespace ICSharpCode.XamlBinding
// } // }
// } // }
public override void Delete() public override bool CanDelete(SharpTreeNode[] nodes)
{
return nodes.OfType<XamlOutlineNode>().All(n => n.Parent != null);
}
public override void Delete(SharpTreeNode[] nodes)
{ {
DeleteCore(); DeleteWithoutConfirmation(nodes);
}
public override void DeleteWithoutConfirmation(SharpTreeNode[] nodes)
{
foreach (XamlOutlineNode xamlNode in nodes.OfType<XamlOutlineNode>()) {
xamlNode.DeleteCore();
}
} }
public override void DeleteCore() void DeleteCore()
{ {
Editor.Document.Remove(Marker.Offset, EndMarker.Offset - Marker.Offset); Editor.Document.Remove(Marker.Offset, EndMarker.Offset - Marker.Offset);
} }

17
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs

@ -132,29 +132,20 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
class WatchRootNode : SharpTreeNode class WatchRootNode : SharpTreeNode
{ {
public override bool CanDrop(DragEventArgs e, int index) public override bool CanPaste(IDataObject data)
{ {
e.Effects = DragDropEffects.None; return data.GetDataPresent(DataFormats.StringFormat);
if (e.Data.GetDataPresent(DataFormats.StringFormat)) {
e.Effects = DragDropEffects.Copy;
return true;
}
return false;
} }
public override void Drop(DragEventArgs e, int index) public override void Paste(IDataObject data)
{ {
if (e.Data == null) return; var watchValue = data.GetData(DataFormats.StringFormat) as string;
if (!e.Data.GetDataPresent(DataFormats.StringFormat)) return;
var watchValue = e.Data.GetData(DataFormats.StringFormat).ToString();
if (string.IsNullOrEmpty(watchValue)) return; if (string.IsNullOrEmpty(watchValue)) return;
var pad = SD.Workbench.GetPad(typeof(WatchPad)).PadContent as WatchPad; var pad = SD.Workbench.GetPad(typeof(WatchPad)).PadContent as WatchPad;
if (pad == null) return; if (pad == null) return;
pad.AddWatch(watchValue); pad.AddWatch(watchValue);
WindowsDebugger.RefreshPads();
} }
} }

10
src/AddIns/Debugger/Debugger.AddIn/TreeModel/SharpTreeNodeAdapter.cs

@ -35,14 +35,16 @@ namespace Debugger.AddIn.Pads.Controls
get { return this.Node.GetChildren != null; } get { return this.Node.GetChildren != null; }
} }
public override bool CanDelete() public override bool CanDelete(SharpTreeNode[] nodes)
{ {
return this.Node.CanDelete; return nodes.All(n => n is SharpTreeNodeAdapter)
&& nodes.Cast<SharpTreeNodeAdapter>().All(n => n.Node.CanDelete);
} }
public override void Delete() public override void Delete(SharpTreeNode[] nodes)
{ {
Parent.Children.Remove(this); foreach (var node in nodes)
node.Parent.Children.Remove(this);
} }
protected override void LoadChildren() protected override void LoadChildren()

21
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichText.cs

@ -158,18 +158,23 @@ namespace ICSharpCode.AvalonEdit.Highlighting
int endOffset = i + 1 < stateChangeOffsets.Length ? stateChangeOffsets[i + 1] : text.Length; int endOffset = i + 1 < stateChangeOffsets.Length ? stateChangeOffsets[i + 1] : text.Length;
Run r = new Run(text.Substring(startOffset, endOffset - startOffset)); Run r = new Run(text.Substring(startOffset, endOffset - startOffset));
HighlightingColor state = stateChanges[i]; HighlightingColor state = stateChanges[i];
if (state.Foreground != null) ApplyColorToTextElement(r, state);
r.Foreground = state.Foreground.GetBrush(null);
if (state.Background != null)
r.Background = state.Background.GetBrush(null);
if (state.FontWeight != null)
r.FontWeight = state.FontWeight.Value;
if (state.FontStyle != null)
r.FontStyle = state.FontStyle.Value;
runs[i] = r; runs[i] = r;
} }
return runs; return runs;
} }
internal static void ApplyColorToTextElement(TextElement r, HighlightingColor state)
{
if (state.Foreground != null)
r.Foreground = state.Foreground.GetBrush(null);
if (state.Background != null)
r.Background = state.Background.GetBrush(null);
if (state.FontWeight != null)
r.FontWeight = state.FontWeight.Value;
if (state.FontStyle != null)
r.FontStyle = state.FontStyle.Value;
}
/// <summary> /// <summary>
/// Produces HTML code for the line, with &lt;span style="..."&gt; tags. /// Produces HTML code for the line, with &lt;span style="..."&gt; tags.

19
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/RichTextModel.cs

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Documents;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.NRefactory.Editor; using ICSharpCode.NRefactory.Editor;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
@ -264,5 +265,23 @@ namespace ICSharpCode.AvalonEdit.Highlighting
index++; index++;
} }
} }
/// <summary>
/// Creates WPF Run instances that can be used for TextBlock.Inlines.
/// </summary>
/// <param name="textSource">The text source that holds the text for this RichTextModel.</param>
public Run[] CreateRuns(ITextSource textSource)
{
Run[] runs = new Run[stateChanges.Count];
for (int i = 0; i < runs.Length; i++) {
int startOffset = stateChangeOffsets[i];
int endOffset = i + 1 < stateChangeOffsets.Count ? stateChangeOffsets[i + 1] : textSource.TextLength;
Run r = new Run(textSource.GetText(startOffset, endOffset - startOffset));
HighlightingColor state = stateChanges[i];
RichText.ApplyColorToTextElement(r, state);
runs[i] = r;
}
return runs;
}
} }
} }

3
src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/RichTextWriter.cs

@ -9,6 +9,9 @@ using ICSharpCode.AvalonEdit.Highlighting;
namespace ICSharpCode.AvalonEdit.Utils namespace ICSharpCode.AvalonEdit.Utils
{ {
// TODO: This class (and derived classes) is currently unused; decide whether to keep it.
// (until this is decided, keep the class internal)
/// <summary> /// <summary>
/// A text writer that supports creating spans of highlighted text. /// A text writer that supports creating spans of highlighted text.
/// </summary> /// </summary>

15
src/Libraries/SharpTreeView/ICSharpCode.TreeView.Demo/FileNode.cs

@ -84,10 +84,15 @@ namespace ICSharpCode.TreeView.Demo
{ {
get { return info.FullName; } get { return info.FullName; }
} }
//
// public override void Paste(IDataObject data) public override bool CanPaste(IDataObject data)
// { {
// Parent.Paste(data); return Parent.CanPaste(data);
// } }
public override void Paste(IDataObject data)
{
Parent.Paste(data);
}
} }
} }

44
src/Libraries/SharpTreeView/ICSharpCode.TreeView.Demo/FileSystemNode.cs

@ -29,47 +29,41 @@ namespace ICSharpCode.TreeView.Demo
{ {
return FullPath; return FullPath;
} }
//
// public override bool CanCopy(SharpTreeNode[] nodes)
// {
// return true;
// }
public override IDataObject Copy(SharpTreeNode[] nodes) public override bool CanCopy(SharpTreeNode[] nodes)
{
return nodes.All(n => n is FileSystemNode);
}
protected override IDataObject GetDataObject(SharpTreeNode[] nodes)
{ {
var data = new DataObject(); var data = new DataObject();
var paths = nodes.OfType<FileSystemNode>().Select(n => n.FullPath).ToArray(); var paths = nodes.OfType<FileSystemNode>().Select(n => n.FullPath).ToArray();
data.SetData(typeof(string[]), paths); data.SetData(DataFormats.FileDrop, paths);
return data; return data;
} }
//
// public override bool CanPaste(IDataObject data) public override bool CanDelete(SharpTreeNode[] nodes)
// {
// return true;
// }
//
public override bool CanDelete()
{ {
return true; return nodes.All(n => n is FileSystemNode);
} }
public override void Delete() public override void Delete(SharpTreeNode[] nodes)
{ {
if (MessageBox.Show("Sure?", "Delete", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { if (MessageBox.Show("Are you sure you want to delete " + nodes.Length + " items?", "Delete", MessageBoxButton.OKCancel) == MessageBoxResult.OK) {
DeleteCore(); DeleteWithoutConfirmation(nodes);
} }
} }
public override void DeleteCore() public override void DeleteWithoutConfirmation(SharpTreeNode[] nodes)
{
this.Parent.Children.Remove(this);
}
public override bool CanDrag(SharpTreeNode[] nodes)
{ {
return true; foreach (var node in nodes) {
if (node.Parent != null)
node.Parent.Children.Remove(node);
}
} }
// ContextMenu menu; // ContextMenu menu;
// //
// public override ContextMenu GetContextMenu() // public override ContextMenu GetContextMenu()

36
src/Libraries/SharpTreeView/ICSharpCode.TreeView.Demo/FolderNode.cs

@ -63,34 +63,46 @@ namespace ICSharpCode.TreeView.Demo
{ {
try { try {
foreach (var p in Directory.GetDirectories(path) foreach (var p in Directory.GetDirectories(path)
.OrderBy(d => Path.GetDirectoryName(d))) { .OrderBy(d => Path.GetDirectoryName(d))) {
Children.Add(new FolderNode(p)); Children.Add(new FolderNode(p));
} }
foreach (var p in Directory.GetFiles(path) foreach (var p in Directory.GetFiles(path)
.OrderBy(f => Path.GetFileName(f))) { .OrderBy(f => Path.GetFileName(f))) {
Children.Add(new FileNode(p)); Children.Add(new FileNode(p));
} }
} }
catch { catch {
} }
} }
public override bool CanDrop(DragEventArgs e, int index) public override bool CanPaste(IDataObject data)
{ {
return e.Data.GetDataPresent(typeof(string[])); return data.GetDataPresent(DataFormats.FileDrop);
} }
public override void Drop(DragEventArgs e, int index) public override void Paste(IDataObject data)
{ {
var paths = e.Data.GetData(typeof(string[])) as string[]; var paths = data.GetData(DataFormats.FileDrop) as string[];
if (paths != null) { if (paths != null) {
for (int i = 0; i < paths.Length; i++) { foreach (var p in paths) {
var p = paths[i];
if (File.Exists(p)) { if (File.Exists(p)) {
Children.Insert(index + i, new FileNode(p)); Children.Add(new FileNode(p));
} else {
Children.Add(new FolderNode(p));
} }
else { }
Children.Insert(index + i, new FolderNode(p)); }
}
public override void Drop(DragEventArgs e, int index)
{
var paths = e.Data.GetData(DataFormats.FileDrop) as string[];
if (paths != null) {
foreach (var p in paths) {
if (File.Exists(p)) {
Children.Insert(index++, new FileNode(p));
} else {
Children.Insert(index++, new FolderNode(p));
} }
} }
} }

106
src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNode.cs

@ -441,7 +441,10 @@ namespace ICSharpCode.TreeView
#region Cut / Copy / Paste / Delete #region Cut / Copy / Paste / Delete
public bool IsCut { get { return false; } } /// <summary>
/// Gets whether the node should render transparently because it is 'cut' (but not actually removed yet).
/// </summary>
public virtual bool IsCut { get { return false; } }
/* /*
static List<SharpTreeNode> cuttedNodes = new List<SharpTreeNode>(); static List<SharpTreeNode> cuttedNodes = new List<SharpTreeNode>();
static IDataObject cuttedData; static IDataObject cuttedData;
@ -538,66 +541,99 @@ namespace ICSharpCode.TreeView
} }
*/ */
public virtual bool CanDelete() public virtual bool CanDelete(SharpTreeNode[] nodes)
{ {
return false; return false;
} }
public virtual void Delete() public virtual void Delete(SharpTreeNode[] nodes)
{ {
throw new NotSupportedException(GetType().Name + " does not support deletion"); throw new NotSupportedException(GetType().Name + " does not support deletion");
} }
public virtual void DeleteCore() public virtual void DeleteWithoutConfirmation(SharpTreeNode[] nodes)
{ {
throw new NotSupportedException(GetType().Name + " does not support deletion"); throw new NotSupportedException(GetType().Name + " does not support deletion");
} }
public virtual IDataObject Copy(SharpTreeNode[] nodes) public virtual bool CanCut(SharpTreeNode[] nodes)
{ {
throw new NotSupportedException(GetType().Name + " does not support copy/paste or drag'n'drop"); return CanCopy(nodes) && CanDelete(nodes);
} }
/* public virtual void Cut(SharpTreeNode[] nodes)
public virtual bool CanCopy(SharpTreeNode[] nodes) {
{ var data = GetDataObject(nodes);
return false; if (data != null) {
} // TODO: default cut implementation should not immediately perform deletion, but use 'IsCut'
Clipboard.SetDataObject(data, copy: true);
public virtual bool CanPaste(IDataObject data) DeleteWithoutConfirmation(nodes);
{
return false;
}
public virtual void Paste(IDataObject data)
{
EnsureLazyChildren();
Drop(data, Children.Count, DropEffect.Copy);
} }
*/ }
#endregion
#region Drag and Drop public virtual bool CanCopy(SharpTreeNode[] nodes)
public virtual bool CanDrag(SharpTreeNode[] nodes) {
return false;
}
public virtual void Copy(SharpTreeNode[] nodes)
{
var data = GetDataObject(nodes);
if (data != null)
Clipboard.SetDataObject(data, copy: true);
}
protected virtual IDataObject GetDataObject(SharpTreeNode[] nodes)
{
return null;
}
public virtual bool CanPaste(IDataObject data)
{ {
return false; return false;
} }
public virtual void Paste(IDataObject data)
{
throw new NotSupportedException(GetType().Name + " does not support copy/paste");
}
#endregion
#region Drag and Drop
public virtual void StartDrag(DependencyObject dragSource, SharpTreeNode[] nodes) public virtual void StartDrag(DependencyObject dragSource, SharpTreeNode[] nodes)
{ {
DragDropEffects effects = DragDropEffects.All; // The default drag implementation works by reusing the copy infrastructure.
if (!nodes.All(n => n.CanDelete())) // Derived classes should override this method
effects &= ~DragDropEffects.Move; var data = GetDataObject(nodes);
DragDropEffects result = DragDrop.DoDragDrop(dragSource, Copy(nodes), effects); if (data == null)
return;
DragDropEffects effects = DragDropEffects.Copy;
if (CanDelete(nodes))
effects |= DragDropEffects.Move;
DragDropEffects result = DragDrop.DoDragDrop(dragSource, data, effects);
if (result == DragDropEffects.Move) { if (result == DragDropEffects.Move) {
foreach (SharpTreeNode node in nodes) DeleteWithoutConfirmation(nodes);
node.DeleteCore();
} }
} }
public virtual bool CanDrop(DragEventArgs e, int index) /// <summary>
/// Gets the possible drop effects.
/// If the method returns more than one of (Copy|Move|Link), the tree view will choose one effect based
/// on the allowed effects and keyboard status.
/// </summary>
public virtual DragDropEffects GetDropEffect(DragEventArgs e, int index)
{ {
return false; // Since the default drag implementation uses Copy(),
// we'll use Paste() in our default drop implementation.
if (CanPaste(e.Data)) {
// If Ctrl is pressed -> copy
// If moving is not allowed -> copy
// Otherwise: move
if ((e.KeyStates & DragDropKeyStates.ControlKey) != 0 || (e.AllowedEffects & DragDropEffects.Move) == 0)
return DragDropEffects.Copy;
return DragDropEffects.Move;
}
return DragDropEffects.None;
} }
internal void InternalDrop(DragEventArgs e, int index) internal void InternalDrop(DragEventArgs e, int index)
@ -612,7 +648,9 @@ namespace ICSharpCode.TreeView
public virtual void Drop(DragEventArgs e, int index) public virtual void Drop(DragEventArgs e, int index)
{ {
throw new NotSupportedException(GetType().Name + " does not support Drop()"); // Since the default drag implementation uses Copy(),
// we'll use Paste() in our default drop implementation.
Paste(e.Data);
} }
#endregion #endregion

7
src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeNodeView.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Windows.Controls; using System.Windows.Controls;
@ -150,8 +151,10 @@ namespace ICSharpCode.TreeView
else { else {
result -= 19; result -= 19;
} }
if (result < 0) if (result < 0) {
throw new InvalidOperationException(); Debug.WriteLine("Negative indent level detected for node " + Node);
result = 0;
}
return result; return result;
} }
} }

78
src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeView.cs

@ -355,7 +355,7 @@ namespace ICSharpCode.TreeView
if (Root != null && !ShowRoot) { if (Root != null && !ShowRoot) {
e.Handled = true; e.Handled = true;
Root.CanDrop(e, Root.Children.Count); e.Effects = Root.GetDropEffect(e, Root.Children.Count);
} }
} }
@ -365,10 +365,12 @@ namespace ICSharpCode.TreeView
if (Root != null && !ShowRoot) { if (Root != null && !ShowRoot) {
e.Handled = true; e.Handled = true;
Root.InternalDrop(e, Root.Children.Count); e.Effects = Root.GetDropEffect(e, Root.Children.Count);
if (e.Effects != DragDropEffects.None)
Root.InternalDrop(e, Root.Children.Count);
} }
} }
internal void HandleDragEnter(SharpTreeViewItem item, DragEventArgs e) internal void HandleDragEnter(SharpTreeViewItem item, DragEventArgs e)
{ {
HandleDragOver(item, e); HandleDragOver(item, e);
@ -377,14 +379,16 @@ namespace ICSharpCode.TreeView
internal void HandleDragOver(SharpTreeViewItem item, DragEventArgs e) internal void HandleDragOver(SharpTreeViewItem item, DragEventArgs e)
{ {
HidePreview(); HidePreview();
e.Effects = DragDropEffects.None;
var target = GetDropTarget(item, e); var target = GetDropTarget(item, e);
if (target != null) { if (target != null) {
e.Handled = true; e.Handled = true;
e.Effects = target.Effect;
ShowPreview(target.Item, target.Place); ShowPreview(target.Item, target.Place);
} }
} }
internal void HandleDrop(SharpTreeViewItem item, DragEventArgs e) internal void HandleDrop(SharpTreeViewItem item, DragEventArgs e)
{ {
try { try {
@ -393,6 +397,7 @@ namespace ICSharpCode.TreeView
var target = GetDropTarget(item, e); var target = GetDropTarget(item, e);
if (target != null) { if (target != null) {
e.Handled = true; e.Handled = true;
e.Effects = target.Effect;
target.Node.InternalDrop(e, target.Index); target.Node.InternalDrop(e, target.Index);
} }
} catch (Exception ex) { } catch (Exception ex) {
@ -400,7 +405,7 @@ namespace ICSharpCode.TreeView
throw; throw;
} }
} }
internal void HandleDragLeave(SharpTreeViewItem item, DragEventArgs e) internal void HandleDragLeave(SharpTreeViewItem item, DragEventArgs e)
{ {
HidePreview(); HidePreview();
@ -414,6 +419,7 @@ namespace ICSharpCode.TreeView
public double Y; public double Y;
public SharpTreeNode Node; public SharpTreeNode Node;
public int Index; public int Index;
public DragDropEffects Effect;
} }
DropTarget GetDropTarget(SharpTreeViewItem item, DragEventArgs e) DropTarget GetDropTarget(SharpTreeViewItem item, DragEventArgs e)
@ -485,13 +491,14 @@ namespace ICSharpCode.TreeView
GetNodeAndIndex(item, place, out node, out index); GetNodeAndIndex(item, place, out node, out index);
if (node != null) { if (node != null) {
e.Effects = DragDropEffects.None; var effect = node.GetDropEffect(e, index);
if (node.CanDrop(e, index)) { if (effect != DragDropEffects.None) {
DropTarget target = new DropTarget() { DropTarget target = new DropTarget() {
Item = item, Item = item,
Place = place, Place = place,
Node = node, Node = node,
Index = index Index = index,
Effect = effect
}; };
targets.Add(target); targets.Add(target);
} }
@ -614,45 +621,78 @@ namespace ICSharpCode.TreeView
static void HandleExecuted_Cut(object sender, ExecutedRoutedEventArgs e) static void HandleExecuted_Cut(object sender, ExecutedRoutedEventArgs e)
{ {
e.Handled = true;
SharpTreeView treeView = (SharpTreeView)sender;
var nodes = treeView.GetTopLevelSelection().ToArray();
if (nodes.Length > 0)
nodes[0].Cut(nodes);
} }
static void HandleCanExecute_Cut(object sender, CanExecuteRoutedEventArgs e) static void HandleCanExecute_Cut(object sender, CanExecuteRoutedEventArgs e)
{ {
e.CanExecute = false; SharpTreeView treeView = (SharpTreeView)sender;
var nodes = treeView.GetTopLevelSelection().ToArray();
e.CanExecute = nodes.Length > 0 && nodes[0].CanCut(nodes);
e.Handled = true;
} }
static void HandleExecuted_Copy(object sender, ExecutedRoutedEventArgs e) static void HandleExecuted_Copy(object sender, ExecutedRoutedEventArgs e)
{ {
e.Handled = true;
SharpTreeView treeView = (SharpTreeView)sender;
var nodes = treeView.GetTopLevelSelection().ToArray();
if (nodes.Length > 0)
nodes[0].Copy(nodes);
} }
static void HandleCanExecute_Copy(object sender, CanExecuteRoutedEventArgs e) static void HandleCanExecute_Copy(object sender, CanExecuteRoutedEventArgs e)
{ {
e.CanExecute = false; SharpTreeView treeView = (SharpTreeView)sender;
var nodes = treeView.GetTopLevelSelection().ToArray();
e.CanExecute = nodes.Length > 0 && nodes[0].CanCopy(nodes);
e.Handled = true;
} }
static void HandleExecuted_Paste(object sender, ExecutedRoutedEventArgs e) static void HandleExecuted_Paste(object sender, ExecutedRoutedEventArgs e)
{ {
SharpTreeView treeView = (SharpTreeView)sender;
var data = Clipboard.GetDataObject();
if (data != null) {
var selectedNode = (treeView.SelectedItem as SharpTreeNode) ?? treeView.Root;
if (selectedNode != null)
selectedNode.Paste(data);
}
e.Handled = true;
} }
static void HandleCanExecute_Paste(object sender, CanExecuteRoutedEventArgs e) static void HandleCanExecute_Paste(object sender, CanExecuteRoutedEventArgs e)
{ {
e.CanExecute = false; SharpTreeView treeView = (SharpTreeView)sender;
var data = Clipboard.GetDataObject();
if (data == null) {
e.CanExecute = false;
} else {
var selectedNode = (treeView.SelectedItem as SharpTreeNode) ?? treeView.Root;
e.CanExecute = selectedNode != null && selectedNode.CanPaste(data);
}
e.Handled = true;
} }
static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e) static void HandleExecuted_Delete(object sender, ExecutedRoutedEventArgs e)
{ {
e.Handled = true;
SharpTreeView treeView = (SharpTreeView)sender; SharpTreeView treeView = (SharpTreeView)sender;
foreach (SharpTreeNode node in treeView.GetTopLevelSelection().ToArray()) var nodes = treeView.GetTopLevelSelection().ToArray();
node.Delete(); if (nodes.Length > 0)
nodes[0].Delete(nodes);
} }
static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e) static void HandleCanExecute_Delete(object sender, CanExecuteRoutedEventArgs e)
{ {
SharpTreeView treeView = (SharpTreeView)sender; SharpTreeView treeView = (SharpTreeView)sender;
e.CanExecute = treeView.GetTopLevelSelection().All(node => node.CanDelete()); var nodes = treeView.GetTopLevelSelection().ToArray();
e.CanExecute = nodes.Length > 0 && nodes[0].CanDelete(nodes);
e.Handled = true;
} }
/// <summary> /// <summary>

4
src/Libraries/SharpTreeView/ICSharpCode.TreeView/SharpTreeViewItem.cs

@ -78,9 +78,7 @@ namespace ICSharpCode.TreeView
Math.Abs(currentPoint.Y - startPoint.Y) >= SystemParameters.MinimumVerticalDragDistance) { Math.Abs(currentPoint.Y - startPoint.Y) >= SystemParameters.MinimumVerticalDragDistance) {
var selection = ParentTreeView.GetTopLevelSelection().ToArray(); var selection = ParentTreeView.GetTopLevelSelection().ToArray();
if (Node.CanDrag(selection)) { Node.StartDrag(this, selection);
Node.StartDrag(this, selection);
}
} }
} }
} }

Loading…
Cancel
Save