Dragging custom controls between cells in a grid in WPF

I have some custom controls that are dynamically added to a custom grid. These controls can span multiple columns and rows (which are the same size). I would like to drag and drop between rows and columns. I can drag individual controls, but they can move without restriction. Even from the grid. I would like to do this so that it can only be dragged inside the grid AND anchor to the column / row it dragged into.

Is there an easy way to do this?

Honestly, if I could get the current row / column, then all I have to do is set the column / row for them, and that would probably do it, and then just worry about keeping it gridded.

+3


source to share


2 answers


I figured out a good and fun way!

I designed the position on the grid where the mouse is turned on in the MouseUp event, and then the relative position of the mouse on the control as it spans multiple rows / columns.

public void getPosition(UIElement element, out int col, out int row)
    {
        DControl control = parent as DControl;
        var point = Mouse.GetPosition(element);
        row = 0;
        col = 0;
        double accumulatedHeight = 0.0;
        double accumulatedWidth = 0.0;

        // calc row mouse was over
        foreach (var rowDefinition in control.RowDefinitions)
        {
            accumulatedHeight += rowDefinition.ActualHeight;
            if (accumulatedHeight >= point.Y)
                break;
            row++;
        }

        // calc col mouse was over
        foreach (var columnDefinition in control.ColumnDefinitions)
        {
            accumulatedWidth += columnDefinition.ActualWidth;
            if (accumulatedWidth >= point.X)
                break;
            col++;
        }
    }

      

Then I pick the relative positions from the normal positions so that when you throw it, it always falls in the upper left corner of the screen. When I move the controls, I use the margins to move them, which at the same time twists the position of the grid, as shown below:



void Chart_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (IsMouseCaptured)
        {
            Point mouseDelta = Mouse.GetPosition(this);
            mouseDelta.Offset(-mouseOffset.X, -mouseOffset.Y);

            Margin = new Thickness(
                Margin.Left + mouseDelta.X,
                Margin.Top + mouseDelta.Y,
                Margin.Right - mouseDelta.X,
                Margin.Bottom - mouseDelta.Y);
        }

    }

    void Chart_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        mouseOffset = Mouse.GetPosition(this);
        CaptureMouse();
        parent.currentObject = this;
    }

      

To deal with this, I just reset the margin.

public void updatePosition()
    {
        Grid.SetRow(this, (int)position.Y);
        Grid.SetColumn(this, (int)position.X);
        Margin = new Thickness();
    }

      

I hope this helps someone else as it was frustrating for me to find the answer and in the end I managed to get a lot of little pieces of how to do things and ended up coming up with my own solution.

+3


source


Is there an easy way to do this?

I would say that the answer to this question is very much dependent on your experience using the Drag and Drop functionality ... for a beginner, I would say that the answer to this question was not that, but for someone with some experience and what Something common sense, it might not be so bad.

To determine which cell the Grid

user mouse ended up with will not be straight. You can handle the event PreviewDragOver

and use a method VisualTreeHelper.HitTest

to check which control is currently:

private void PreviewDragOver(object sender, DragEventArgs e)
{
    HitTestResult hitTestResult = VisualTreeHelper.HitTest(adornedUIElement, 
        e.GetPosition(adornedUIElement));
    Control controlUnderMouse = hitTestResult.VisualHit.GetParentOfType<Control>();
}

      



Method GetParentOfType

is a useful extension method I created, but you can easily convert it to a regular method:

public static T GetParentOfType<T>(this DependencyObject element) where T : DependencyObject
{
    Type type = typeof(T);
    if (element == null) return null;
    DependencyObject parent = VisualTreeHelper.GetParent(element);
    if (parent == null && ((FrameworkElement)element).Parent is DependencyObject) parent = ((FrameworkElement)element).Parent;
    if (parent == null) return null;
    else if (parent.GetType() == type || parent.GetType().IsSubclassOf(type)) return parent as T;
    return GetParentOfType<T>(parent);
}

      

Of course, once you have Control

in your variable controlUnderMouse

, you will still be doing significant work as you work through UIElement

until you get to Grid

. you can of course use the method GetParentOfType

to make your job easier.

+1


source







All Articles