#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

309 lines
7.4 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Collections;
using System.Collections.Specialized;
using System.Windows.Data;
using System.Diagnostics;
using System.Windows.Input;
using System.Windows.Documents;
using System.Windows.Media;
using SharpDevelop.XamlDesigner.Converters;
namespace SharpDevelop.XamlDesigner.Controls
{
public class TreeBox : ListBox
{
static TreeBox()
{
SelectionModeProperty.OverrideMetadata(typeof(TreeBox),
new FrameworkPropertyMetadata(SelectionMode.Extended));
HorizontalContentAlignmentProperty.OverrideMetadata(typeof(TreeBox),
new FrameworkPropertyMetadata(HorizontalAlignment.Stretch));
}
public TreeBox()
{
SetResourceReference(StyleProperty, typeof(ListBox));
listener = new CollectionListener(this, "TreeSource");
listener.CollectionChanged += new NotifyCollectionChangedEventHandler(listener_CollectionChanged);
}
CollectionListener listener;
void listener_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
GenerateRootItems();
}
public static readonly DependencyProperty CoreStyleProperty =
DependencyProperty.Register("CoreStyle", typeof(Style), typeof(TreeBox));
public Style CoreStyle
{
get { return (Style)GetValue(CoreStyleProperty); }
set { SetValue(CoreStyleProperty, value); }
}
public static readonly DependencyProperty TreeSourceProperty =
DependencyProperty.Register("TreeSource", typeof(IEnumerable), typeof(TreeBox));
public IEnumerable TreeSource
{
get { return (IEnumerable)GetValue(TreeSourceProperty); }
set { SetValue(TreeSourceProperty, value); }
}
public static readonly DependencyProperty AllowDragProperty =
DependencyProperty.Register("AllowDrag", typeof(bool), typeof(TreeBox));
public bool AllowDrag
{
get { return (bool)GetValue(AllowDragProperty); }
set { SetValue(AllowDragProperty, value); }
}
internal void OnItemsChanged(TreeBoxItemCore core, NotifyCollectionChangedEventArgs e)
{
if (core.IsExpanded) {
int index = Items.IndexOf(core);
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
var newCore = CreateCore(e.NewItems[0], core);
Items.Insert(index + e.NewStartingIndex + 1, newCore);
break;
case NotifyCollectionChangedAction.Remove:
Items.RemoveAt(index + e.OldStartingIndex + 1);
break;
default:
Collapse(core);
Expand(core);
break;
}
}
}
void GenerateRootItems()
{
Items.Clear();
if (TreeSource != null) {
foreach (var item in TreeSource) {
var core = CreateCore(item, null);
Items.Add(core);
}
}
}
public void Expand(TreeBoxItemCore core)
{
int index = Items.IndexOf(core);
foreach (var item in core.Items) {
var newCore = CreateCore(item, core);
Items.Insert(++index, newCore);
}
}
public void Collapse(TreeBoxItemCore core)
{
int index = Items.IndexOf(core) + 1;
while (index < Items.Count && (Items[index] as TreeBoxItemCore).Level > core.Level) {
Items.RemoveAt(index);
}
}
protected override DependencyObject GetContainerForItemOverride()
{
var listBoxItem = new TreeBoxItem();
listBoxItem.SetBinding(ListBoxItem.IsSelectedProperty, "IsSelected");
return listBoxItem;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var core = item as TreeBoxItemCore;
base.PrepareContainerForItemOverride(core, core.Item);
}
TreeBoxItemCore CreateCore(object item, TreeBoxItemCore parent)
{
var core = new TreeBoxItemCore();
core.Item = item;
core.ParentTree = this;
if (parent != null) {
core.Level = parent.Level + 1;
}
core.DataContext = item;
core.SetBinding(FrameworkElement.StyleProperty,
new Binding("CoreStyle") { Source = this });
return core;
}
#region Drag & Drop
InsertInfo insert;
internal void TryStartDrag()
{
if (AllowDrag) {
insert = new InsertInfo();
insert.Items = SelectedItems.Cast<object>().ToArray();
insert.Adorner = new GeneralAdorner(this) {
Child = new OutlineInsertLine()
};
DragDrop.DoDragDrop(this, this, DragDropEffects.All);
}
}
protected override void OnDragEnter(DragEventArgs e)
{
ProcessDrag(e);
}
protected override void OnDragOver(DragEventArgs e)
{
ProcessDrag(e);
}
void ProcessDrag(DragEventArgs e)
{
e.Effects = DragDropEffects.None;
e.Handled = true;
if (insert != null) {
HidePreview();
insert.Copy = Keyboard.IsKeyDown(Key.LeftCtrl);
var container = (e.OriginalSource as DependencyObject).FindAncestor<TreeBoxItem>();
if (container != null) {
insert.Hover = container;
var y = e.GetPosition(container).Y;
var h = container.ActualHeight;
if (y < h / 5) {
insert.Part = Part.Before;
}
else if (y > h - h / 5) {
insert.Part = Part.After;
}
else {
insert.Part = Part.Inside;
}
if (CanDrop()) {
e.Effects = DragDropEffects.Move;
ShowPreview();
return;
}
}
}
}
bool CanDrop()
{
if (insert.Part == Part.Inside) {
insert.TargetParent = insert.Hover.Core.Item;
insert.TargetIndex = insert.Hover.Core.Items.Count;
}
else if (insert.Part == Part.Before) {
SetTarget(insert.Hover.Core, 0);
}
else {
SetTarget(insert.Hover.Core, 1);
}
return CanInsert(insert.TargetParent, insert.Items, insert.TargetIndex, insert.Copy);
}
void SetTarget(TreeBoxItemCore core, int shift)
{
var index = Items.IndexOf(core);
for (int i = index - 1; i >= 0; i--) {
var item = Items[i] as TreeBoxItemCore;
if (item.Level < core.Level) {
insert.TargetParent = item.Item;
insert.TargetIndex = item.Items.IndexOf(core) + shift;
return;
}
}
insert.TargetParent = TreeSource;
insert.TargetIndex = Items.IndexOf(core) + shift;
}
void ShowPreview()
{
insert.Hover.Background = FindResource("OutlineInsertBackground") as Brush;
if (insert.Part == Part.Before || insert.Part == Part.After) {
var p = insert.Part == Part.Before ? new Point() : new Point(0, insert.Hover.ActualHeight);
var y = insert.Hover.TransformToAncestor(this).Transform(p).Y;
var element = insert.Adorner.Child as FrameworkElement;
element.Width = insert.Hover.ActualWidth;
element.Margin = new Thickness(0, y, 0, 0);
AdornerLayer.GetAdornerLayer(this).Add(insert.Adorner);
}
}
void HidePreview()
{
if (insert.Hover != null) {
insert.Hover.ClearValue(TreeBoxItem.BackgroundProperty);
AdornerLayer.GetAdornerLayer(this).Remove(insert.Adorner);
}
}
protected override void OnDrop(DragEventArgs e)
{
HidePreview();
}
protected virtual bool CanInsert(object parent, IEnumerable<object> items, int index, bool copy)
{
return true;
}
protected virtual void Insert(object parent, IEnumerable<object> items, int index, bool copy)
{
}
protected virtual bool CanDelete(IEnumerable<object> items)
{
return true;
}
protected virtual void Delete(IEnumerable<object> items)
{
}
class InsertInfo
{
public object[] Items;
public bool Copy;
public TreeBoxItem Hover;
public Part Part;
public object TargetParent;
public int TargetIndex;
public GeneralAdorner Adorner;
}
enum Part
{
Before, Inside, After
}
#endregion
}
}