HI,
if you want use additional click event (button click) you must change your code.
MainWindow:
<Window x:Class="TreeviewExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:TreeviewExample"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:MainViewModel x:Key="vm"/>
<local:IntVisConverter x:Key="IntConverter"/>
</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource vm}}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<GroupBox Header="Features" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Margin="10,10,10,10">
<!-- Features ListBox -->
<ListBox x:Name="featureListBox"
AllowDrop="True"
ItemsSource="{Binding ListBoxSource}" Margin="5,10,5,10">
<i:Interaction.Behaviors>
<local:ListBoxDragDropBehavior />
</i:Interaction.Behaviors>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<TextBlock Text="{Binding ItemName}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
<GroupBox Header="Template" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Margin="10,10,10,10">
<Grid>
<TreeView Name="templateTreeview"
ItemsSource="{Binding TreeViewSource}"
FontSize="14"
AllowDrop="True" Margin="5,5,5,10">
<i:Interaction.Behaviors>
<local:TreeViewDragDropBehavior />
</i:Interaction.Behaviors>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:ViewItem}" ItemsSource="{Binding Path=ViewItems}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=ItemName}" Margin="0,0,10,0" />
<Button Name="DeleteTreeViewItem"
Background="Transparent"
BorderBrush="Transparent"
Visibility="{Binding Path=IsVisible,Converter={StaticResource IntConverter}}"
Command="{Binding Cmd, Source={StaticResource vm}}"
CommandParameter="{Binding}">
<Image Source="delete_cross.png" Height="15" />
</Button>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</GroupBox>
</Grid>
</Window>
MainViewModel:
using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace TreeviewExample
{
public class MainViewModel
{
public ObservableCollection<ViewItem> ListBoxSource { get; set; } = new ObservableCollection<ViewItem>();
public ObservableCollection<ViewItem> TreeViewSource { get; set; } = new ObservableCollection<ViewItem>();
// in ctor load demo data
public MainViewModel()
{
for (int i = 1; i < 20; i++) ListBoxSource.Add(new ViewItem($"ListBoxItem {i}") { Parent = ListBoxSource });
ViewItem defaultView = new ViewItem("Root", 1) { Parent = TreeViewSource };
TreeViewSource.Add(defaultView);
for (int i = 1; i < 10; i++) defaultView.ViewItems.Add(new ViewItem($"TreeViewItem {i}") { Parent = defaultView.ViewItems });
}
// property for commands
public ICommand Cmd { get => new RelayCommand(CmdExec); }
private void CmdExec(object obj)
{
var item = obj as ViewItem;
if (item == null) return;
item.Parent.Remove(item);
}
}
#pragma warning disable CS8612 // Nullability of reference types in type doesn't match implicitly implemented member.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes).
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _action;
public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
public void Execute(object o) => _action(o);
public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
TreeViewDragDropBehavior:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace TreeviewExample
{
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
public class TreeViewDragDropBehavior : Behavior<UIElement>
{
protected override void OnAttached()
{
AssociatedObject.PreviewMouseLeftButtonDown += tv_PreviewMouseLeftButtonDown;
AssociatedObject.MouseMove += tv_MouseMove;
AssociatedObject.DragOver += tv_DragOver;
AssociatedObject.Drop += Tv_Drop;
AssociatedObject.DragLeave += tv_DragLeave;
}
// for saving TreeViewItem to drag
TreeViewItem draggedTVI = null;
// save TreeViewItem to drag
private void tv_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
draggedTVI = FindAnchestor<TreeViewItem>((DependencyObject)e.OriginalSource);
}
// start Drag&Drop when mouse is moved and there's a saved TreeViewItem
private void tv_MouseMove(object sender, MouseEventArgs e)
{
if (draggedTVI != null)
{
// Find the data behind the TreeViewItem
ViewItem dragData = draggedTVI.DataContext as ViewItem;
// Initialize the drag & drop operation
DragDrop.DoDragDrop(draggedTVI, dragData, DragDropEffects.Move);
// reset saved TreeViewItem
draggedTVI = null;
}
}
// highlight target
private void tv_DragOver(object sender, DragEventArgs e)
{
TreeViewItem tvi = FindAnchestor<TreeViewItem>((DependencyObject)e.OriginalSource);
if (tvi != null) tvi.Background = Brushes.LightBlue;
}
//
private void Tv_Drop(object sender, DragEventArgs e)
{
// if no data to drop return
if (!e.Data.GetDataPresent(typeof(ViewItem))) return;
// store the drop target
ViewItem targetItem = (e.OriginalSource as TextBlock)?.DataContext as ViewItem;
if (targetItem == null) return;
ViewItem data = (ViewItem)e.Data.GetData(typeof(ViewItem));
targetItem.ViewItems.Add(data);
// change parent collection
data.Parent.Remove(data);
data.Parent = targetItem.ViewItems;
// reset background on target TreeViewItem
TreeViewItem tvi = FindAnchestor<TreeViewItem>((DependencyObject)e.OriginalSource);
if (tvi != null) tvi.Background = Brushes.White;
}
// reset background on leaved possible target TreeViewItem
private void tv_DragLeave(object sender, DragEventArgs e)
{
TreeViewItem tvi = FindAnchestor<TreeViewItem>((DependencyObject)e.OriginalSource);
if (tvi != null) tvi.Background = Brushes.White;
}
// Helper to search up the VisualTree
private static T FindAnchestor<T>(DependencyObject current) where T : DependencyObject
{
do
{
if (current is T) return (T)current;
current = VisualTreeHelper.GetParent(current);
} while (current != null);
return null;
}
}
}