阅读 243

WPF DataGrid行拖拽

效果

我在GitHub开源地址:
使用MIT开源HandyControl样式库:

首先定义一个行为

public static class DragDropRowBehavior
    {
        private static DataGrid dataGrid;

        private static Popup popup;

        private static bool enable;

        private static object draggedItem;

        public static object DraggedItem
        {
            get { return DragDropRowBehavior.draggedItem; }
            set { DragDropRowBehavior.draggedItem = value; }
        }

        public static Popup GetPopupControl(DependencyObject obj)
        {
            return (Popup)obj.GetValue(PopupControlProperty);
        }

        public static void SetPopupControl(DependencyObject obj, Popup value)
        {
            obj.SetValue(PopupControlProperty, value);
        }

        // Using a DependencyProperty as the backing store for PopupControl.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PopupControlProperty =
            DependencyProperty.RegisterAttached("PopupControl", typeof(Popup), typeof(DragDropRowBehavior), new UIPropertyMetadata(null, OnPopupControlChanged));

        private static void OnPopupControlChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue == null || !(e.NewValue is Popup))
            {
                throw new ArgumentException("Popup Control should be set", "PopupControl");
            }
            popup = e.NewValue as Popup;

            dataGrid = depObject as DataGrid;
            // Check if DataGrid
            if (dataGrid == null)
                return;


            if (enable && popup != null)
            {
                dataGrid.BeginningEdit += new EventHandler(OnBeginEdit);
                dataGrid.CellEditEnding += new EventHandler(OnEndEdit);
                dataGrid.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(OnMouseLeftButtonUp);
                dataGrid.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
                dataGrid.MouseMove += new MouseEventHandler(OnMouseMove);
            }
            else
            {
                dataGrid.BeginningEdit -= new EventHandler(OnBeginEdit);
                dataGrid.CellEditEnding -= new EventHandler(OnEndEdit);
                dataGrid.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(OnMouseLeftButtonUp);
                dataGrid.MouseLeftButtonDown -= new MouseButtonEventHandler(OnMouseLeftButtonDown);
                dataGrid.MouseMove -= new MouseEventHandler(OnMouseMove);

                dataGrid = null;
                popup = null;
                draggedItem = null;
                IsEditing = false;
                IsDragging = false;
            }
        }

        public static bool GetEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(EnabledProperty);
        }

        public static void SetEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(EnabledProperty, value);
        }

        // Using a DependencyProperty as the backing store for Enabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EnabledProperty =
            DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(DragDropRowBehavior), new UIPropertyMetadata(false, OnEnabledChanged));

        private static void OnEnabledChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs e)
        {
            //Check if value is a Boolean Type
            if (e.NewValue is bool == false)
                throw new ArgumentException("Value should be of bool type", "Enabled");

            enable = (bool)e.NewValue;

        }

        public static bool IsEditing { get; set; }

        public static bool IsDragging { get; set; }

        private static void OnBeginEdit(object sender, DataGridBeginningEditEventArgs e)
        {
            IsEditing = true;
            //in case we are in the middle of a drag/drop operation, cancel it...
            if (IsDragging) ResetDragDrop();
        }

        private static void OnEndEdit(object sender, DataGridCellEditEndingEventArgs e)
        {
            IsEditing = false;
        }


        /// 
        /// Initiates a drag action if the grid is not in edit mode.
        /// 
        private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (IsEditing) return;
            
            var row = UIHelpers.TryFindFromPoint((UIElement)sender, e.GetPosition(dataGrid));
            if (row == null || row.IsEditing) return;

            //set flag that indicates we‘re capturing mouse movements
            IsDragging = true;
            DraggedItem = row.Item;
        }

        /// 
        /// Completes a drag/drop operation.
        /// 
        private static void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!IsDragging || IsEditing)
            {
                return;
            }
            dataGrid.Cursor = Cursors.Arrow;

            //get the target item
            var targetItem = dataGrid.SelectedItem;

            if (targetItem == null || !ReferenceEquals(DraggedItem, targetItem))
            {
                //get target index
                var targetIndex = ((dataGrid).ItemsSource as IList).IndexOf(targetItem);

                //remove the source from the list
                ((dataGrid).ItemsSource as IList).Remove(DraggedItem);

                //move source at the target‘s location
                ((dataGrid).ItemsSource as IList).Insert(targetIndex, DraggedItem);

                //select the dropped item
                dataGrid.SelectedItem = DraggedItem;
            }

            //reset
            ResetDragDrop();
        }

        /// 
        /// Closes the popup and resets the
        /// grid to read-enabled mode.
        /// 
        private static void ResetDragDrop()
        {
            IsDragging = false;
            popup.IsOpen = false;
            dataGrid.IsReadOnly = false;
        }

        /// 
        /// Updates the popup‘s position in case of a drag/drop operation.
        /// 
        private static void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (!IsDragging || e.LeftButton != MouseButtonState.Pressed) return;
            if (dataGrid.Cursor != Cursors.SizeAll) dataGrid.Cursor = Cursors.SizeAll;
            popup.DataContext = DraggedItem;
            //display the popup if it hasn‘t been opened yet
            if (!popup.IsOpen)
            {
                //switch to read-only mode
                dataGrid.IsReadOnly = true;

                //make sure the popup is visible
                popup.IsOpen = true;
            }


            Size popupSize = new Size(popup.ActualWidth, popup.ActualHeight);
            popup.PlacementRectangle = new Rect(e.GetPosition(dataGrid), popupSize);

            //make sure the row under the grid is being selected
            Point position = e.GetPosition(dataGrid);
            var row = UIHelpers.TryFindFromPoint(dataGrid, position);
            if (row != null) dataGrid.SelectedItem = row.Item;
        }

    }

供行为使用的UI工具类

public static class UIHelpers
    {
        #region find parent

        /// 
        /// Finds a parent of a given item on the visual tree.
        /// 
        /// The type of the queried item.
        /// A direct or indirect child of the
        /// queried item.
        /// The first parent item that matches the submitted
        /// type parameter. If not matching item can be found, a null
        /// reference is being returned.
        public static T TryFindParent(DependencyObject child)
          where T : DependencyObject
        {
            //get parent item
            DependencyObject parentObject = GetParentObject(child);

            //we‘ve reached the end of the tree
            if (parentObject == null) return null;

            //check if the parent matches the type we‘re looking for
            T parent = parentObject as T;
            if (parent != null)
            {
                return parent;
            }
            else
            {
                //use recursion to proceed with next level
                return TryFindParent(parentObject);
            }
        }


        /// 
        /// This method is an alternative to WPF‘s
        ///  method, which also
        /// supports content elements. Do note, that for content element,
        /// this method falls back to the logical tree of the element.
        /// 
        /// The item to be processed.
        /// The submitted item‘s parent, if available. Otherwise
        /// null.
        public static DependencyObject GetParentObject(DependencyObject child)
        {
            if (child == null) return null;
            ContentElement contentElement = child as ContentElement;

            if (contentElement != null)
            {
                DependencyObject parent = ContentOperations.GetParent(contentElement);
                if (parent != null) return parent;

                FrameworkContentElement fce = contentElement as FrameworkContentElement;
                return fce != null ? fce.Parent : null;
            }

            //if it‘s not a ContentElement, rely on VisualTreeHelper
            return VisualTreeHelper.GetParent(child);
        }

        #endregion


        #region update binding sources

        /// 
        /// Recursively processes a given dependency object and all its
        /// children, and updates sources of all objects that use a
        /// binding expression on a given property.
        /// 
        /// The dependency object that marks a starting
        /// point. This could be a dialog window or a panel control that
        /// hosts bound controls.
        /// The properties to be updated if
        ///  or one of its childs provide it along
        /// with a binding expression.
        public static void UpdateBindingSources(DependencyObject obj,
                                  params DependencyProperty[] properties)
        {
            foreach (DependencyProperty depProperty in properties)
            {
                //check whether the submitted object provides a bound property
                //that matches the property parameters
                BindingExpression be = BindingOperations.GetBindingExpression(obj, depProperty);
                if (be != null) be.UpdateSource();
            }

            int count = VisualTreeHelper.GetChildrenCount(obj);
            for (int i = 0; i < count; i++)
            {
                //process child items recursively
                DependencyObject childObject = VisualTreeHelper.GetChild(obj, i);
                UpdateBindingSources(childObject, properties);
            }
        }

        #endregion


        /// 
        /// Tries to locate a given item within the visual tree,
        /// starting with the dependency object at a given position. 
        /// 
        /// The type of the element to be found
        /// on the visual tree of the element at the given location.
        /// The main element which is used to perform
        /// hit testing.
        /// The position to be evaluated on the origin.
        public static T TryFindFromPoint(UIElement reference, Point point)
          where T : DependencyObject
        {
            DependencyObject element = reference.InputHitTest(point)
                                         as DependencyObject;
            if (element == null) return null;
            else if (element is T) return (T)element;
            else return TryFindParent(element);
        }
    }

XAML中加入命名空间,后使用


            
                
            
            
                
                    
                    
                    
                
            
        

原文:https://www.cnblogs.com/Stay627/p/15023454.html

文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐