WPF-DragDrop拖拽文字、文件、图片...

目录

拖拽说明

一、拖拽文字

二、拖拽文件

三、拖拽图片

四、控件随鼠标移动

五、托拽集合控件数据项

六、拖拽移动控件

七、使用gong-wpf-dragdrop拖拽框架 

1、DropHandler实现复制(非移动)示例代码

2、DropHandler实现删除

3、Xaml示例代码

4、业务逻辑示例代码

5、效果图


拖拽说明

拖拽推荐框架:gong-wpf-dragdrop

GitHub地址:Usage · punker76/gong-wpf-dragdrop Wiki (github.com)

本章主要使用拖拽三个相关属性及事件:

 属性AllowDrop:是否允许作为拖拽目标

 事件DragDrop.DragEnter:当对象源进入目标容器边缘时触发

 事件DragDrop.Drop:将对象拖放到放置目标时触发

一、拖拽文字

拖拽任意文字到Label中显示

示例代码:见拖拽文件

 

二、拖拽文件

拖拽文件到Label显示文件内容

示例代码:

            <Label Width="300"
                   Height="300"
                   AllowDrop="True"
                   Background="White"
                   DragDrop.DragEnter="Label_DragEnter"
                   DragDrop.Drop="Label_Drop" />
        private void Label_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(Button)))
            { 
                e.Effects= DragDropEffects.Copy;
            }

        }

        private void Label_Drop(object sender, DragEventArgs e)
        {
            Label label=sender as Label;
            if (e.Data.GetDataPresent(DataFormats.Text))
            {
                var data = e.Data.GetData(DataFormats.Text);
                label.Content = data.ToString();
            }
            else if (e.Data.GetDataPresent(DataFormats.FileDrop))
            { 
                string path=((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
                label.Content =File.ReadAllText(path);
            }
        }

 

三、拖拽图片

拖拽图片到图片控件显示

示例代码;

        <Grid Width="300" Background="LightBlue" AllowDrop="True" DragDrop.DragEnter="Grid_DragEnter" DragDrop.Drop="Grid_Drop">
            <Image  x:Name="img"/>
        </Grid>
        private void Grid_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            { 
                e.Effects = DragDropEffects.Copy;
            }
        }

        private void Grid_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string path = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
                Bitmap bitmap=new Bitmap(path);
                ImageSource source =Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(),IntPtr.Zero,Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
                img.Source=source;

            }
        }

 

四、控件随鼠标移动

主要通过三个鼠标事件实现:

事件PreviewMouseDown:鼠标按下触发
事件PreviewMouseMove:鼠标移动触发
事件PreviewMouseUp :鼠标松开触发

示例代码:

        <Button Width="50"
                Height="40"
                Background="LightBlue"
                Content="Move" HorizontalAlignment="Left" VerticalAlignment="Top"
                PreviewMouseDown="Button_PreviewMouseDown"
                PreviewMouseMove="Button_PreviewMouseMove"
                PreviewMouseUp="Button_PreviewMouseUp" />

RenderTransform:元素呈现位置的转换信息 

        public bool isMouseDown = false;
        public Point mouseDownPosition;
        public Point mouseDownControlPosition;
        private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            isMouseDown = true;
            mouseDownPosition = e.GetPosition(this);
            var ctl = sender as UIElement;
            var transform = ctl.RenderTransform as TranslateTransform;
            if (transform == null)
            {
                transform = new TranslateTransform();
                ctl.RenderTransform = transform;
            }
            mouseDownControlPosition = new Point(transform.X, transform.Y);
            ctl.CaptureMouse();
        }

        private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (isMouseDown)
            {
                var ctl = sender as UIElement;
                var pos = e.GetPosition(this);
                var dp = pos - mouseDownControlPosition;
                var translate = ctl.RenderTransform as TranslateTransform;
                translate.X = mouseDownControlPosition.X + dp.X;
                translate.Y = mouseDownControlPosition.Y + dp.Y;
            }
        }

        private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            var ctl = sender as UIElement;
            isMouseDown = false;
            ctl.ReleaseMouseCapture();
        }

五、托拽集合控件数据项

主要实现代码如下:

        private void ListView_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                var listView = sender as ListView;
                if (listView.SelectedItem != null)
                {
                    var vector = listView.SelectedItem as VectorBase;
                    var dragData = new DataObject(typeof(VectorBase), vector);
                    DragDrop.DoDragDrop(listView, dragData, DragDropEffects.Move);
                }
            }
        }

        private void ListView_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(VectorBase)))
            {
                var listView = sender as ListView;
                var vector = e.Data.GetData(typeof(VectorBase)) as VectorBase;
                var pos = e.GetPosition(listView);
                var oldIndex = listView.Items.IndexOf(vector);
                var newIndex = GetIndexOfPoint(listView, pos);
                if (newIndex != -1)
                {
                    var list = listView.ItemsSource as ObservableCollection<VectorBase>;
                    list.Move(oldIndex, newIndex);
                }
            }
        }

        /// <summary>
        /// 获取指定Point在ListView对应项的索引
        /// </summary>
        /// <param name="listView"></param>
        /// <param name="pos"></param>
        /// <returns></returns>
        private int GetIndexOfPoint(ListView listView, Point pos)
        {
            for (int i = 0; i < listView.Items.Count; i++)
            {
                var item = listView.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;
                if (item != null)
                {
                    var itemPos = item.TranslatePoint(new Point(0, 0), listView);
                    Rect itemBound = new Rect(itemPos, new Size(item.ActualWidth, item.ActualHeight));
                    if (itemBound.Contains(pos))
                    {
                        return i;
                    }
                }
            }
            return -1;
        }

六、拖拽移动控件

 主要用到MouseLeftButtonDown、Drop两个事件实现移动控件

示例代码:

前端:

        <WrapPanel x:Name="wrap1"
                   Width="300"
                   Height="400"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Top"
                   AllowDrop="True"
                   Background="YellowGreen"
                   Drop="WrapPanel_Drop" />
        <WrapPanel Name="wrap2"
                   Grid.Column="1"
                   Width="300"
                   Height="400"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Top"
                   Background="DarkMagenta"
                   MouseLeftButtonDown="WrapPanel_MouseLeftButtonDown">
            <ItemsControl d:ItemsSource="{d:SampleData ItemCount=5}" ItemsSource="{Binding MyList}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel Orientation="Horizontal" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.Template>
                    <ControlTemplate TargetType="ItemsControl">
                        <ScrollViewer hc:ScrollViewerAttach.Orientation="Horizontal"
                                      HorizontalScrollBarVisibility="Auto"
                                      VerticalScrollBarVisibility="Hidden">
                            <ItemsPresenter />
                        </ScrollViewer>
                    </ControlTemplate>
                </ItemsControl.Template>
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type model:Student}">
                        <Border BorderBrush="Black"
                                BorderThickness="2"
                                CornerRadius="3">
                            <Label Width="80" Height="40"
                                   Background="YellowGreen"
                                   Content="{Binding Name}"
                                   FontSize="20"
                                   FontWeight="Bold" />
                        </Border>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </WrapPanel>

后台:

        private void WrapPanel_Drop(object sender, DragEventArgs e)
        {
            var obj=e.Data;
            object data = obj.GetData(obj.GetFormats()[0]);
            if (data is UIElement)
            {
                wrap2.Children.Remove(data as UIElement);
                wrap1.Children.Add(data as UIElement);
               
            }
        }

        private void WrapPanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var obj=e.Source;
            if (obj is UIElement ) 
            {
                DragDrop.DoDragDrop(obj as UIElement, obj, DragDropEffects.Move);
            }
        }

效果展示:

拖拽后 

七、使用gong-wpf-dragdrop拖拽框架 

 拖拽推荐框架:gong-wpf-dragdrop

GitHub地址:Usage · punker76/gong-wpf-dragdrop Wiki (github.com)

主要使用框架依赖属性:

dd:DragDrop.IsDragSource="True"//是否作为拖拽源
dd:DragDrop.IsDropTarget="False"//是否作为投递目标

dd:DragDrop.UseDefaultDragAdorner="True"//使用默认的拖拽装饰器

dd:DragDrop.UseDefaultEffectDataTemplate="True"//使用默认的阴影数据模板

dd:DragDrop.EffectMoveAdornerTemplate//指定移动时的阴影装饰器模板

dd:DragDrop.DropHandler="{Binding MyDropHandler}"//投下时执行处理器

注意 :框架默认行为是移动,可通过DropHandler实现复制功能

1、DropHandler实现复制(非移动)示例代码

        参考GitHub中Demo代码


    internal class CopyDropHandler : IDropTarget
    {
#if true
        /// <summary>
        /// Test the specified drop information for the right data.
        /// </summary>
        /// <param name="dropInfo">The drop information.</param>
        public static bool CanAcceptData(IDropInfo dropInfo)
        {
            if (dropInfo?.DragInfo == null)
            {
                return false;
            }

            if (!dropInfo.IsSameDragDropContextAsSource)
            {
                return false;
            }

            // do not drop on itself
            var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter)
                                 && dropInfo.VisualTargetItem is TreeViewItem;
            if (isTreeViewItem && dropInfo.VisualTargetItem == dropInfo.DragInfo.VisualSourceItem)
            {
                return false;
            }

            if (dropInfo.TargetCollection is null)
            {
                return false;
            }

            if (ReferenceEquals(dropInfo.DragInfo.SourceCollection, dropInfo.TargetCollection))
            {
                var targetList = dropInfo.TargetCollection.TryGetList();
                return targetList != null;
            }

            if (TestCompatibleTypes(dropInfo.TargetCollection, dropInfo.Data))
            {
                var isChildOf = IsChildOf(dropInfo.VisualTargetItem, dropInfo.DragInfo.VisualSourceItem);
                return !isChildOf;
            }

            return false;
        }

        public static IEnumerable ExtractData(object data)
        {
            if (data is IEnumerable enumerable and not string)
            {
                return enumerable;
            }

            return Enumerable.Repeat(data, 1);
        }

        /// <summary>
        /// Clears the current selected items and selects the given items.
        /// </summary>
        /// <param name="dropInfo">The drop information.</param>
        /// <param name="items">The items which should be select.</param>
        /// <param name="applyTemplate">if set to <c>true</c> then for all items the ApplyTemplate will be invoked.</param>
        /// <param name="focusVisualTarget">if set to <c>true</c> the visual target will be focused.</param>
        /// <exception cref="System.ArgumentNullException"><paramref name="dropInfo" /> is <see langword="null" /></exception>
        /// <exception cref="System.ArgumentNullException"><paramref name="dropInfo" /> is <see langword="null" /></exception>
        public static void SelectDroppedItems(IDropInfo dropInfo, IEnumerable items, bool applyTemplate = true, bool focusVisualTarget = true)
        {
            if (dropInfo == null) throw new ArgumentNullException(nameof(dropInfo));
            if (items == null) throw new ArgumentNullException(nameof(items));

            if (dropInfo.VisualTarget is ItemsControl itemsControl)
            {
                var tvItem = dropInfo.VisualTargetItem as TreeViewItem;
                var tvItemIsExpanded = tvItem != null && tvItem.HasHeader && tvItem.HasItems && tvItem.IsExpanded;

                var itemsParent = tvItemIsExpanded
                    ? tvItem
                    : dropInfo.VisualTargetItem != null
                        ? ItemsControl.ItemsControlFromItemContainer(dropInfo.VisualTargetItem)
                        : itemsControl;
                itemsParent ??= itemsControl;

                (dropInfo.DragInfo.VisualSourceItem as TreeViewItem)?.ClearSelectedItems();
                itemsParent.ClearSelectedItems();

                var selectDroppedItems = dropInfo.VisualTarget is TabControl || (dropInfo.VisualTarget != null && DragDrop.GetSelectDroppedItems(dropInfo.VisualTarget));
                if (selectDroppedItems)
                {
                    foreach (var item in items)
                    {
                        if (applyTemplate)
                        {
                            // call ApplyTemplate for TabItem in TabControl to avoid this error:
                            //
                            // System.Windows.Data Error: 4 : Cannot find source for binding with reference
                            var container = itemsParent.ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
                            container?.ApplyTemplate();
                        }

                        itemsParent.SetItemSelected(item, true);
                    }

                    if (focusVisualTarget)
                    {
                        itemsControl.Focus();
                    }
                }
            }
        }

        /// <summary>
        /// Determines whether the data of the drag drop action should be copied otherwise moved.
        /// </summary>
        /// <param name="dropInfo">The DropInfo with a valid DragInfo.</param>
        public static bool ShouldCopyData(IDropInfo dropInfo)
        {
            // default should always the move action/effect
            if (dropInfo?.DragInfo == null)
            {
                return false;
            }

            var copyData = ((dropInfo.DragInfo.DragDropCopyKeyState != default) && dropInfo.KeyStates.HasFlag(dropInfo.DragInfo.DragDropCopyKeyState))
                           || dropInfo.DragInfo.DragDropCopyKeyState.HasFlag(DragDropKeyStates.LeftMouseButton);
            copyData = copyData
                       && dropInfo.DragInfo.SourceItem is not HeaderedContentControl
                       && dropInfo.DragInfo.SourceItem is not HeaderedItemsControl
                       && dropInfo.DragInfo.SourceItem is not ListBoxItem;
            return copyData;
        }

        protected static int GetInsertIndex(IDropInfo dropInfo)
        {
            var insertIndex = dropInfo.UnfilteredInsertIndex;

            if (dropInfo.VisualTarget is ItemsControl itemsControl)
            {
                if (itemsControl.Items is IEditableCollectionView editableItems)
                {
                    var newItemPlaceholderPosition = editableItems.NewItemPlaceholderPosition;
                    if (newItemPlaceholderPosition == NewItemPlaceholderPosition.AtBeginning && insertIndex == 0)
                    {
                        ++insertIndex;
                    }
                    else if (newItemPlaceholderPosition == NewItemPlaceholderPosition.AtEnd && insertIndex == itemsControl.Items.Count)
                    {
                        --insertIndex;
                    }
                }
            }

            return insertIndex;
        }

        protected static void Move(IList list, int sourceIndex, int destinationIndex)
        {
            if (!list.IsObservableCollection())
            {
                throw new ArgumentException("ObservableCollection<T> was expected", nameof(list));
            }

            if (sourceIndex != destinationIndex)
            {
                var method = list.GetType().GetMethod("Move", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
                _ = method?.Invoke(list, new object[] { sourceIndex, destinationIndex });
            }
        }

        protected static bool IsChildOf(UIElement targetItem, UIElement sourceItem)
        {
            var parent = ItemsControl.ItemsControlFromItemContainer(targetItem);

            while (parent != null)
            {
                if (parent == sourceItem)
                {
                    return true;
                }

                parent = ItemsControl.ItemsControlFromItemContainer(parent);
            }

            return false;
        }

        protected static bool TestCompatibleTypes(IEnumerable target, object data)
        {
            bool InterfaceFilter(Type t, object o) => (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));

            var enumerableInterfaces = target.GetType().FindInterfaces(InterfaceFilter, null);
            var enumerableTypes = from i in enumerableInterfaces
                                  select i.GetGenericArguments().Single();

            if (enumerableTypes.Any())
            {
                var dataType = TypeUtilities.GetCommonBaseClass(ExtractData(data));
                return enumerableTypes.Any(t => t.IsAssignableFrom(dataType));
            }
            else
            {
                return target is IList or ICollectionView;
            }
        }

#if !NETCOREAPP3_1_OR_GREATER
        /// <inheritdoc />
        public void DragEnter(IDropInfo dropInfo)
        {
            // nothing here
        }
#endif

        /// <inheritdoc />
        public virtual void DragOver(IDropInfo dropInfo)
        {
            if (CanAcceptData(dropInfo))
            {
                var copyData = ShouldCopyData(dropInfo);
                var sourceList = dropInfo.DragInfo.SourceCollection.TryGetList();
                var destinationList = dropInfo.TargetCollection.TryGetList();
                var isSameCollection = sourceList.IsSameObservableCollection(destinationList);
                if (isSameCollection)
                    dropInfo.Effects = DragDropEffects.Move;
                else
                    dropInfo.Effects = copyData ? DragDropEffects.Move : DragDropEffects.Copy;
                var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter) && dropInfo.VisualTargetItem is TreeViewItem;
                dropInfo.DropTargetAdorner = isTreeViewItem ? DropTargetAdorners.Highlight : DropTargetAdorners.Insert;

                //var copyData = ShouldCopyData(dropInfo);
                //dropInfo.Effects = copyData ? DragDropEffects.Move : DragDropEffects.Copy;
                //var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter) && dropInfo.VisualTargetItem is TreeViewItem;
                //dropInfo.DropTargetAdorner = isTreeViewItem ? DropTargetAdorners.Highlight : DropTargetAdorners.Insert;
            }
        }

#if !NETCOREAPP3_1_OR_GREATER
        /// <inheritdoc />
        public void DragLeave(IDropInfo dropInfo)
        {
            // nothing here
        }
#endif

        /// <inheritdoc />
        public virtual void Drop(IDropInfo dropInfo)
        {
            if (dropInfo?.DragInfo == null)
            {
                return;
            }

            var insertIndex = GetInsertIndex(dropInfo);
            var destinationList = dropInfo.TargetCollection.TryGetList();
            var data = ExtractData(dropInfo.Data).OfType<object>().ToList();
            bool isSameCollection = false;
            var sourceList = dropInfo.DragInfo.SourceCollection.TryGetList();
            isSameCollection = sourceList.IsSameObservableCollection(destinationList);
#if false
            var copyData = ShouldCopyData(dropInfo);
            if (!copyData)
            {
                var sourceList = dropInfo.DragInfo.SourceCollection.TryGetList();
                if (sourceList != null)
                {
                    isSameCollection = sourceList.IsSameObservableCollection(destinationList);
                    if (!isSameCollection)
                    {
                        foreach (var o in data)
                        {
                            var index = sourceList.IndexOf(o);
                            if (index != -1)
                            {
                                sourceList.RemoveAt(index);

                                // If source is destination too fix the insertion index
                                if (destinationList != null && ReferenceEquals(sourceList, destinationList) && index < insertIndex)
                                {
                                    --insertIndex;
                                }
                            }
                        }
                    }
                }
            }
#endif

            if (destinationList != null)
            {
                var objects2Insert = new List<object>();

                // check for cloning
                var cloneData = dropInfo.Effects.HasFlag(DragDropEffects.Copy) || dropInfo.Effects.HasFlag(DragDropEffects.Link);

                foreach (var o in data)
                {
                    var obj2Insert = o;
                    if (cloneData)
                    {
                        if (o is ICloneableDragItem cloneableItem)
                        {
                            obj2Insert = cloneableItem.CloneItem(dropInfo);
                        }
                        else if (o is ICloneable cloneable)
                        {
                            obj2Insert = cloneable.Clone();
                        }
                    }

                    objects2Insert.Add(obj2Insert);

                    if (!cloneData && isSameCollection)
                    {
                        var index = destinationList.IndexOf(o);
                        if (index != -1)
                        {
                            if (insertIndex > index)
                            {
                                insertIndex--;
                            }

                            Move(destinationList, index, insertIndex++);
                        }
                    }
                    else
                    {
                        destinationList.Insert(insertIndex++, obj2Insert);
                    }

                    if (obj2Insert is IDragItemSource dragItemSource)
                    {
                        dragItemSource.ItemDropped(dropInfo);
                    }
                }

                SelectDroppedItems(dropInfo, objects2Insert);
            }
        }
    }
#else
        public void DragEnter(IDropInfo dropInfo)
        {

        }

        public void DragOver(IDropInfo dropInfo)
        {
            var itemsouce = dropInfo.Data as Student;
            if (itemsouce != null)
            {
                dropInfo.DropTargetAdorner = DropTargetAdorners.Highlight;
                dropInfo.Effects = DragDropEffects.Copy;
            }
        }

        public void DragLeave(IDropInfo dropInfo)
        {

        }

        public void Drop(IDropInfo dropInfo)
        {
            var sourceitem = dropInfo.Data as Student;
            var targetitem = dropInfo.TargetItem as ObservableCollection<Student>;
            targetitem.Add(sourceitem);
        }
    }
#endif

2、DropHandler实现删除

只需更改DragOverDrop逻辑

示例代码:

        public virtual void DragOver(IDropInfo dropInfo)
        {
            if (CanAcceptData(dropInfo))
            {
                var sourceControl = dropInfo.DragInfo.VisualSource;
                var candelete = (bool)sourceControl.GetValue(Attach.DragDropAttach.CanDeleteProperty);
                if (candelete)
                    dropInfo.Effects = DragDropEffects.Move;
                else
                    dropInfo.Effects = DragDropEffects.None;
                var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter) && dropInfo.VisualTargetItem is TreeViewItem;
                dropInfo.DropTargetAdorner = isTreeViewItem ? DropTargetAdorners.Highlight : DropTargetAdorners.Insert;
            }
        }
        public virtual void Drop(IDropInfo dropInfo)
        {
            if (dropInfo?.DragInfo == null)
            {
                return;
            }

            var data = ExtractData(dropInfo.Data).OfType<object>().ToList();
            var sourceList = dropInfo.DragInfo.SourceCollection.TryGetList();
            if (dropInfo.Effects.HasFlag(DragDropEffects.Move))
            {
                foreach (var o in data)
                {
                    var index = sourceList.IndexOf(o);
                    if (index != -1)
                    {
                        sourceList.RemoveAt(index);
                    }
                }
            }
        }

3、Xaml示例代码

    <Window.DataContext>
        <vm:MainWinViewModelcs />
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid>
            <GroupBox Width="NaN"
                      Background="LightBlue"
                      FontSize="20"
                      FontStyle="Italic"
                      FontWeight="ExtraBlack"
                      Header="源区">
                <ItemsControl Margin="5"
                              attach:DragDropAttach.CanDelete="False"
                              d:ItemsSource="{d:SampleData ItemCount=3}"
                              dd:DragDrop.IsDragSource="True"
                              dd:DragDrop.IsDropTarget="False"
                              dd:DragDrop.UseDefaultDragAdorner="True"
                              Background="White"
                              FontFamily="{Binding ElementName=listbox, Path=SelectedItem}"
                              ItemsSource="{Binding Students}">
                    <dd:DragDrop.EffectMoveAdornerTemplate>
                        <DataTemplate>
                            <Border BorderBrush="Blue" BorderThickness="2">
                                <TextBlock Text="移动到这" />
                            </Border>
                        </DataTemplate>
                    </dd:DragDrop.EffectMoveAdornerTemplate>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate DataType="{x:Type model:Student}">
                            <Border BorderBrush="Black" BorderThickness="3">
                                <TextBlock Text="{Binding Name}" />
                            </Border>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </GroupBox>
        </Grid>
        <GroupBox Grid.Column="1"
                  Background="LightGreen"
                  FontSize="20"
                  FontStretch="UltraExpanded"
                  FontWeight="ExtraBlack"
                  Header="目标区">
            <ListBox Margin="5"
                     attach:DragDropAttach.CanDelete="True"
                     d:ItemsSource="{d:SampleData ItemCount=4}"
                     dd:DragDrop.DropHandler="{Binding CopyDropHandler}"
                     dd:DragDrop.IsDragSource="True"
                     dd:DragDrop.IsDropTarget="True"
                     dd:DragDrop.UseDefaultDragAdorner="True"
                     ItemsSource="{Binding StudentsTar}"
                     SelectedIndex="{Binding SelectIndex}"
                     SelectedItem="{Binding SelectStu}">
                <dd:DragDrop.EffectMoveAdornerTemplate>
                    <DataTemplate>
                        <Border BorderBrush="Black" BorderThickness="1">
                            <TextBlock FontSize="20"
                                       Foreground="Black"
                                       Text="移动到这" />
                        </Border>
                    </DataTemplate>
                </dd:DragDrop.EffectMoveAdornerTemplate>
                <ListBox.Resources>
                    <depend:MyProxy x:Key="myproxy" DataContext="{Binding}" />
                </ListBox.Resources>
                <ListBox.ItemTemplate>
                    <DataTemplate DataType="{x:Type model:Student}">
                        <Border BorderBrush="Black" BorderThickness="3">
                            <TextBlock Text="{Binding Name}" />
                        </Border>
                    </DataTemplate>
                </ListBox.ItemTemplate>
                <ListBox.ItemContainerStyle>
                    <Style TargetType="ListBoxItem">
                        <Setter Property="ContextMenu">
                            <Setter.Value>
                                <ContextMenu DataContext="{Binding Source={StaticResource myproxy}}">
                                    <MenuItem Command="{Binding DataContext.CopyItemCmd}" Header="复制" />
                                    <MenuItem Command="{Binding DataContext.DeleteCmd}" Header="删除" />
                                </ContextMenu>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListBox.ItemContainerStyle>
            </ListBox>
        </GroupBox>
        <GroupBox Grid.Column="2"
                  Background="LightGray"
                  FontSize="20"
                  FontWeight="ExtraBlack"
                  Header="字体选择">
            <StackPanel>
                <ListBox x:Name="listbox"
                         Height="300"
                         FontSize="20"
                         FontWeight="DemiBold" />
                <TextBox x:Name="tbox"
                         Height="30"
                         Text="@@@@@@"
                         TextDecorations="Underline" />
                <ItemsControl Width="150"
                              Height="80"
                              HorizontalAlignment="Center"
                              VerticalAlignment="Center"
                              HorizontalContentAlignment="Center"
                              VerticalContentAlignment="Center"
                              dd:DragDrop.DropHandler="{Binding DeleteDropHandler}"
                              dd:DragDrop.IsDropTarget="True"
                              Background="LightGreen">
                    <ItemsControl.Template>
                        <ControlTemplate TargetType="ItemsControl">
                            <Border Width="NaN"
                                    BorderBrush="Red"
                                    BorderThickness="5">
                                <StackPanel>
                                    <TextBlock Height="40"
                                               HorizontalAlignment="Center"
                                               VerticalAlignment="Center"
                                               FontSize="30"
                                               FontWeight="Heavy"
                                               Foreground="Red"
                                               Text="垃圾箱" />
                                    <TextBlock Height="30"
                                               HorizontalAlignment="Center"
                                               VerticalAlignment="Center"
                                               FontSize="20"
                                               FontWeight="ExtraLight"
                                               Foreground="Red"
                                               Text="垃圾往这扔" />
                                </StackPanel>
                            </Border>
                        </ControlTemplate>
                    </ItemsControl.Template>
                    <ItemsControl.ToolTip>
                        <TextBlock Text="放进这里删除" />
                    </ItemsControl.ToolTip>
                </ItemsControl>
            </StackPanel>
        </GroupBox>
    </Grid>

注意:示例代码中使用了菜单项,菜单项无法直接实现命令绑定:

原因:由于菜单项属于控件细节,存在于视觉树中,逻辑树中看不到,无法找到逻辑树中的DataContext上下文资源,所以绑定失败。

解决方法:使用代理方式,将细节控件中的DataContext绑定到逻辑树中控件的DataContext,这样就能找到逻辑树中的DataContext资源了。

4、业务逻辑示例代码

    internal class MainWinViewModelcs:BindableBase
    {
        private int _selectIndex;

        public int SelectIndex
        {   
            get => _selectIndex;
            set => SetProperty(ref _selectIndex, value);
        }

        private Student _selectStu;

        public Student SelectStu
        {
            get => _selectStu;
            set => SetProperty(ref _selectStu, value);
        }

        private ObservableCollection<Student> _students;

		public ObservableCollection<Student> Students
		{
			get => _students;
			set => SetProperty(ref _students, value);
		}

        private ObservableCollection<Student> _studentsTar;

        public ObservableCollection<Student> StudentsTar
        {
            get => _studentsTar;
            set => SetProperty(ref _studentsTar, value);
        }

        public DelegateCommand DeleteCmd { get; set; }

        public DelegateCommand CopyItemCmd { get; set; }

        /// <summary>
        /// 移除选中项
        /// </summary>
        public void Delete()
        { 
            StudentsTar.RemoveAt(SelectIndex);
        }

        /// <summary>
        /// 复制选中项
        /// </summary>
        public void CopyItem()
        {
            StudentsTar.Add(SelectStu.Clone() as Student);       
        }

        /// <summary>
        /// 投下复制Handler
        /// </summary>
        public CopyDropHandler CopyDropHandler { get; set; }

        /// <summary>
        /// 投下删除Handler
        /// </summary>
        public DeleteDropHandler DeleteDropHandler { get; set; }

        public MainWinViewModelcs()
        {
            DeleteDropHandler = new DeleteDropHandler();
            CopyDropHandler = new CopyDropHandler();
            StudentsTar = new ObservableCollection<Student>();
            CopyItemCmd = new DelegateCommand(CopyItem);
            DeleteCmd = new DelegateCommand(Delete);
            Students = new ObservableCollection<Student>() { 
                new Student(){ Id=1,Name="Auston1"},
                new Student(){ Id=2,Name="Auston2"},
                new Student(){ Id=3,Name="Auston3"},
                new Student(){ Id=4,Name="Auston4"},
            };
        }
    }

5、效果图

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 WPF DragDrop 例子: XAML 代码: ```xml <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="450" Width="800"> <Grid> <StackPanel Orientation="Horizontal" Margin="10"> <TextBlock Text="Drag me:" Margin="0,0,10,0" /> <TextBlock Text="Hello, world!" Background="LightGray" Width="100" Height="50" PreviewMouseLeftButtonDown="TextBlock_PreviewMouseLeftButtonDown" PreviewMouseMove="TextBlock_PreviewMouseMove" PreviewMouseLeftButtonUp="TextBlock_PreviewMouseLeftButtonUp" /> </StackPanel> <StackPanel Orientation="Horizontal" Margin="10"> <TextBlock Text="Drop here:" Margin="0,0,10,0" /> <Border BorderBrush="Black" BorderThickness="1" Width="100" Height="50" AllowDrop="True" Drop="Border_Drop" /> </StackPanel> </Grid> </Window> ``` C# 代码: ```csharp using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace WpfApp1 { public partial class MainWindow : Window { private bool isDragging = false; private Point startPoint; public MainWindow() { InitializeComponent(); } private void TextBlock_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { startPoint = e.GetPosition(null); isDragging = true; } private void TextBlock_PreviewMouseMove(object sender, MouseEventArgs e) { if (isDragging && e.LeftButton == MouseButtonState.Pressed) { Point position = e.GetPosition(null); Vector offset = startPoint - position; if (Math.Abs(offset.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(offset.Y) > SystemParameters.MinimumVerticalDragDistance) { DataObject data = new DataObject("myFormat", "Hello, world!"); DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Copy); isDragging = false; } } } private void TextBlock_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { isDragging = false; } private void Border_Drop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent("myFormat")) { string text = (string)e.Data.GetData("myFormat"); ((Border)sender).Child = new TextBlock { Text = text, Background = Brushes.LightGray }; } } } } ``` 这个例子演示了如何在 WPF 中实现拖放操作。我们创建了一个包含两个 StackPanel 的 Window,第一个 StackPanel 包含一个 TextBlock,可以被拖动,第二个 StackPanel 包含一个 Border,可以接受拖放操作。当用户按下鼠标左键并移动 TextBlock 时,如果移动距离超过一定阈值,就会触发拖放操作。在拖放操作中,我们将一个字符串放入 DataObject 中,并指定数据格式为 "myFormat"。在 Border 的 Drop 事件中,我们检查数据格式是否为 "myFormat",如果是,就将字符串显示在 Border 中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值