【问题标题】:TreeView with DragDrop and HierarchicalDataTemplate and other Control Elements as TreeViewItem具有 DragDrop 和 HierarchicalDataTemplate 以及其他控件元素的 TreeView 作为 TreeViewItem
【发布时间】:2014-08-15 21:46:11
【问题描述】:

我试图让 TreeView 工作,它使用 HierarchialDataTemplate 将节点绑定到 ObservableCollection。 TreeViewItems 是其中包含复选框和组合框的网格。所有这些都可以正常工作,但我没有设法让拖放功能正常工作。

代码基于 TreeView, HierarchicalDataTemplate and recursive Datahttp://www.codeproject.com/Articles/55168/Drag-and-Drop-Feature-in-WPF-TreeView-Control

<Window x:Class="TreeView_HierarchicalDataTemplate.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:TreeView_HierarchicalDataTemplate="clr-namespace:TreeView_HierarchicalDataTemplate"
    Title="MainWindow" x:Name="mainWindow" Height="350" Width="525">

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>


<Grid>

    <TreeView Name="TreeView_After" AllowDrop="True" DataContext="{Binding ElementName=mainWindow, Path=TreeModel}" ItemsSource="{Binding Items}">

        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <EventSetter Event="TreeViewItem.DragOver" Handler="TreeView_After_DragOver"/>
                <EventSetter Event="TreeViewItem.Drop" Handler="TreeView_After_Drop"/>
                <EventSetter Event="TreeViewItem.MouseMove" Handler="TreeView_After_MouseMove"/>
                <EventSetter Event="TreeViewItem.MouseDown" Handler="TreeView_After_MouseDown"/>
            </Style>

        </TreeView.ItemContainerStyle>

        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type TreeView_HierarchicalDataTemplate:NodeViewModel}" ItemsSource="{Binding Children}">

                <Grid Background="LightBlue">
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                    </Grid.RowDefinitions>

                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>

                    <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Name}"></TextBlock>
                    <GridSplitter Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Column="0" Width="5"/>
                    <CheckBox Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Row="0" Grid.Column="1" Margin="5,5,0,0">activated</CheckBox>
                    <GridSplitter Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Column="0" Width="5"/>
                    <StackPanel Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Row="0" Grid.Column="2" Orientation="Horizontal">
                        <TextBlock Margin="5">Action:</TextBlock>
                        <ComboBox>
                            <TextBlock>Move To</TextBlock>
                        </ComboBox>
                        <TextBlock Margin="5">C:\\Videos\Folder\aVideo.mkv</TextBlock>
                    </StackPanel>
                    <GridSplitter Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Column="1" Width="5"/>
                    <StackPanel Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Row="0" Grid.Column="3" Orientation="Horizontal">
                        <TextBlock Margin="5">Duplicate of:</TextBlock>
                        <ComboBox>
                            <TextBlock>None</TextBlock>
                        </ComboBox>
                    </StackPanel>

                </Grid>

            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>

</Grid>

这是 Observable 集合

public class TreeViewModel
{
    public ObservableCollection<NodeViewModel> Items { get; set; }
}

public class NodeViewModel : UIElement
{
    public NodeViewModel()
    {
        Show = true;
    }

    public string Id { get; set; }
    public string Name { get; set; }
    public bool Show { get; set; }
    public ObservableCollection<NodeViewModel> Children { get; set; }
}

但是这个鼠标按下事件不起作用

private void TreeView_After_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Left)
        {
            _lastMouseDown = e.GetPosition(TreeView_After);
        }

    }

此外,如果我从 UIElement 派生 NodeViewModel,我只有从元素(UIElement)到容器(NodeViewModel)的这种类型转换才能工作。但是,如果我从 UIElement 派生 NodeViewModel,TreeView 将不再显示:(

private NodeViewModel GetNearestContainer(UIElement element)
    {
        // Walk up the element tree to the nearest tree view item.
        NodeViewModel container = element as NodeViewModel;
        while ((container == null) && (element != null))
        {
            element = VisualTreeHelper.GetParent(element) as UIElement;
            container = element as NodeViewModel;
        }
        return container;
    }

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    在 Rohit Vats 的帮助下,我得到了这样的帮助:

    MainWindow.xaml:

    <Window x:Class="TreeView_HierarchicalDataTemplate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:TreeView_HierarchicalDataTemplate="clr-namespace:TreeView_HierarchicalDataTemplate"
        Title="MainWindow" x:Name="mainWindow" Height="350" Width="525">
    
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVis" />
    </Window.Resources>
    
    
    <Grid>
    
        <TreeView Name="TreeView_After" AllowDrop="True" DataContext="{Binding ElementName=mainWindow, Path=TreeModel}" ItemsSource="{Binding Items}">
    
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <EventSetter Event="TreeViewItem.DragOver" Handler="TreeView_After_DragOver"/>
                    <EventSetter Event="TreeViewItem.Drop" Handler="TreeView_After_Drop"/>
                    <EventSetter Event="TreeViewItem.MouseMove" Handler="TreeView_After_MouseMove"/>
                </Style>
    
            </TreeView.ItemContainerStyle>
    
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type TreeView_HierarchicalDataTemplate:NodeViewModel}" ItemsSource="{Binding Children}">
    
                    <Grid Background="LightBlue" MouseDown="TreeView_After_MouseDown">
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Name}"></TextBlock>
                        <GridSplitter Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Column="0" Width="5"/>
                        <CheckBox Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Row="0" Grid.Column="1" Margin="5,5,0,0">activated</CheckBox>
                        <GridSplitter Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Column="0" Width="5"/>
                        <StackPanel Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Row="0" Grid.Column="2" Orientation="Horizontal">
                            <TextBlock Margin="5">Action:</TextBlock>
                            <ComboBox>
                                <TextBlock>Move To</TextBlock>
                            </ComboBox>
                            <TextBlock Margin="5">C:\\Videos\Folder\aVideo.mkv</TextBlock>
                        </StackPanel>
                        <GridSplitter Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Column="1" Width="5"/>
                        <StackPanel Visibility="{Binding Path=Show, Converter={StaticResource BoolToVis}}" Grid.Row="0" Grid.Column="3" Orientation="Horizontal">
                            <TextBlock Margin="5">Duplicate of:</TextBlock>
                            <ComboBox>
                                <TextBlock>None</TextBlock>
                            </ComboBox>
                        </StackPanel>
    
                    </Grid>
    
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    
    </Grid>
    

    树视图模型:

    public class TreeViewModel
    {
        public ObservableCollection<NodeViewModel> Items { get; set; }
    }
    
    public class NodeViewModel
    {
        public NodeViewModel()
        {
            Show = true;
        }
    
        public string Id { get; set; }
        public string Name { get; set; }
        public bool Show { get; set; }
        public ObservableCollection<NodeViewModel> Children { get; set; }
    }
    

    主窗口代码:

    public partial class MainWindow : Window
    {
        TreeViewModel TreeViewModel_After;
    
    
        public MainWindow()
        {
            TreeViewModel_After = new TreeViewModel();
    
            TreeViewModel_After.Items = new ObservableCollection<NodeViewModel>{
                           new NodeViewModel { Name = "Root", Children =  new ObservableCollection<NodeViewModel> {
                              new NodeViewModel { Name = "Level1" ,  Children = new ObservableCollection<NodeViewModel>{ 
                                  new NodeViewModel{ Name = "Level2"}}} } }};
    
            InitializeComponent();
    
    
        }
    
        public TreeViewModel TreeModel
        {
            get
            {
                return TreeViewModel_After;
            }
        }
    
    
    
    
    
        Point _lastMouseDown;
        NodeViewModel draggedItem, _target;
    
    
        private void TreeView_After_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ChangedButton == MouseButton.Left)
            {
                _lastMouseDown = e.GetPosition(TreeView_After);
            }
    
        }
    
    
        private bool CheckGridSplitter(UIElement element)
        {
            if (element is GridSplitter)
            {
                return true;
            }
    
            GridSplitter GridSplitter = FindParent<GridSplitter>(element);
    
            if (GridSplitter != null)
            {
                return true;
            }
            return false;
    
        }
    
    
        private void TreeView_After_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    UIElement element = e.OriginalSource as UIElement;
                    bool bGridSplitter = CheckGridSplitter(element);
    
    
                    Point currentPosition = e.GetPosition(TreeView_After);
    
    
                    if ((Math.Abs(currentPosition.X - _lastMouseDown.X) > 10.0) ||
                        (Math.Abs(currentPosition.Y - _lastMouseDown.Y) > 10.0))
                    {
                        draggedItem = (NodeViewModel)TreeView_After.SelectedItem;
    
                        if ( (draggedItem != null) && !bGridSplitter)
                        {
                            DragDropEffects finalDropEffect = DragDrop.DoDragDrop(TreeView_After, TreeView_After.SelectedValue,
                                DragDropEffects.Move);
                            //Checking target is not null and item is dragging(moving)
                            if ((finalDropEffect == DragDropEffects.Move) && (_target != null))
                            {
    
                                // A Move drop was accepted
                                if (draggedItem.Name != _target.Name)
                                {
                                    CopyItem(draggedItem, _target);
                                    _target = null;
                                    draggedItem = null;
                                }      
    
    
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
            }
        }
        private void TreeView_After_DragOver(object sender, DragEventArgs e)
        {
            try
            {
    
                Point currentPosition = e.GetPosition(TreeView_After);
    
    
                if ((Math.Abs(currentPosition.X - _lastMouseDown.X) > 10.0) ||
                    (Math.Abs(currentPosition.Y - _lastMouseDown.Y) > 10.0))
                {
                    // Verify that this is a valid drop and then store the drop target
                    NodeViewModel item = GetNearestContainer(e.OriginalSource as UIElement);
                    if (CheckDropTarget(draggedItem, item))
                    {
                        e.Effects = DragDropEffects.Move;
                    }
                    else
                    {
                        e.Effects = DragDropEffects.None;
                    }
                }
                e.Handled = true;
            }
            catch (Exception)
            {
            }
        }
        private void TreeView_After_Drop(object sender, DragEventArgs e)
        {
            try
            {
                e.Effects = DragDropEffects.None;
                e.Handled = true;
    
                // Verify that this is a valid drop and then store the drop target
                NodeViewModel TargetItem = GetNearestContainer(e.OriginalSource as UIElement);
                if (TargetItem != null && draggedItem != null)
                {
                    _target = TargetItem;
                    e.Effects = DragDropEffects.Move;
    
                }
            }
            catch (Exception)
            {
            }
    
    
    
        }
    
        private bool CheckDropTarget(NodeViewModel _sourceItem, NodeViewModel _targetItem)
        {
            //Check whether the target item is meeting your condition
            bool _isEqual = false;
    
            if(_sourceItem.Name != _targetItem.Name )
            {
                _isEqual = true;
            }
    
            return _isEqual;
    
        }
    
    
        private void CopyItem(NodeViewModel _sourceItem, NodeViewModel _targetItem)
        {
    
            //Asking user wether he want to drop the dragged TreeViewItem here or not
            if (MessageBox.Show("Would you like to drop " + _sourceItem.Name + " into " + _targetItem.Name + "", "", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
            {
                try
                {
                    _targetItem.Children.Add(_sourceItem);
                }
                catch (Exception)
                {
    
                }
            }
    
        }
    
    
        private NodeViewModel GetNearestContainer(UIElement element)
        {
            // Walk up the element tree to the nearest tree view item.
            TreeViewItem UIContainer = FindParent<TreeViewItem>(element);
            NodeViewModel NVContainer = null;
    
            if (UIContainer != null)
            {
                NVContainer = UIContainer.DataContext as NodeViewModel;
            }
            return NVContainer;
        }
    
    
        private static Parent FindParent<Parent>(DependencyObject child)
                where Parent : DependencyObject
        {
            DependencyObject parentObject = child;
            parentObject = VisualTreeHelper.GetParent(parentObject);
    
            //check if the parent matches the type we're looking for
            if (parentObject is Parent || parentObject == null)
            {
                return parentObject as Parent;
            }
            else
            {
                //use recursion to proceed with next level
                return FindParent<Parent>(parentObject);
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-25
      • 1970-01-01
      • 1970-01-01
      • 2018-02-23
      相关资源
      最近更新 更多