Как автоматически прокрутить DataGridView во время перетаскивания - PullRequest
4 голосов
/ 02 апреля 2010

Одна из форм в моем приложении на C # .NET имеет несколько DataGridView, которые реализуют перетаскивание для перемещения строк. Перетаскивание в большинстве случаев работает правильно, но мне было трудно перевести DataGridViews в AutoScroll - когда строка перетаскивается в верхней или нижней части окна, чтобы прокрутить ее в этом направлении.

До сих пор я пытался реализовать версию этого решения. У меня есть класс ScrollingGridView, унаследованный от DataGridView, который реализует описанный таймер, и, согласно отладчику, таймер срабатывает соответствующим образом, но код таймера:

const int WM_VSCROLL = 277;
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

private void ScrollingGridViewTimerTick(object sender, EventArgs e)
{
    SendMessage(Handle, WM_VSCROLL, (IntPtr)scrollDirectionInt, IntPtr.Zero);
}

, насколько я могу судить, ничего не делает, возможно, потому, что у меня есть несколько DataGridViews в форме. Я также пытался изменить свойство AutoScrollOffset, но это тоже ничего не делало. Исследование классов DataGridView и ScrollBar, по-видимому, не предполагает каких-либо других команд или функций, которые фактически будут выполнять прокрутку DataGridView. Может кто-нибудь помочь мне с функцией, которая фактически прокручивает DataGridView, или каким-либо другим способом решить проблему?

Ответы [ 3 ]

2 голосов
/ 08 сентября 2018
private void TargetReasonGrid_DragOver(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Move;

    //Converts window position to user control position (otherwise you can use MousePosition.Y)
    int mousepos = PointToClient(Cursor.Position).Y;

    //If the mouse is hovering over the bottom 5% of the grid
    if (mousepos > (TargetReasonGrid.Location.Y + (TargetReasonGrid.Height * 0.95)))
    {
        //If the first row displayed isn't the last row in the grid
        if (TargetReasonGrid.FirstDisplayedScrollingRowIndex < TargetReasonGrid.RowCount - 1)
        {
            //Increase the first row displayed index by 1 (scroll down 1 row)
            TargetReasonGrid.FirstDisplayedScrollingRowIndex = TargetReasonGrid.FirstDisplayedScrollingRowIndex + 1;
        }
    }

    //If the mouse is hovering over the top 5% of the grid
    if (mousepos < (TargetReasonGrid.Location.Y + (TargetReasonGrid.Height * 0.05)))
    {
        //If the first row displayed isn't the first row in the grid
        if (TargetReasonGrid.FirstDisplayedScrollingRowIndex > 0)
        {
            //Decrease the first row displayed index by 1 (scroll up 1 row)
            TargetReasonGrid.FirstDisplayedScrollingRowIndex = TargetReasonGrid.FirstDisplayedScrollingRowIndex - 1;
        }
    }
}

Множество полезных ответов, просто подумал, что я бы добавил менее сложное решение этой проблемы. Код выше вызывается, когда строки перетаскиваются внутри DataGridView. Шахта называется "TargetReasonGrid".

Я добавил примечания, которые объясняют, что я делаю, но вот шаги, изложенные:

  1. Преобразовать положение мыши так, чтобы оно относилось к расположению сетки (в пределах вашей формы / элемента управления)

  2. Установить мнимые области на краю отображаемой сетки, где перемещение мыши вызовет прокрутку

  3. Убедитесь, что у вас есть разные строки для прокрутки до

  4. Прокрутка с шагом 1 строка

Благодаря C4u (прокомментированному выше) дал мне идею «воображаемых областей».

1 голос
/ 05 апреля 2010

Я давно не смотрел этот код. Но некоторое время назад я реализовал DataGridView, который поддерживал только это.

    class DragOrderedDataGridView : System.Windows.Forms.DataGridView
{
    public delegate void RowDroppedEventHangler(object source, DataGridViewRow sourceRow, DataGridViewRow destinationRow);
    public event RowDroppedEventHangler RowDropped;

    bool bDragging = false;
    System.Windows.Forms.DataGridView.HitTestInfo hti = null;
    System.Threading.Timer scrollTimer = null;
    delegate void SetScrollDelegate(int value);

    public bool AllowDragOrdering { get; set; }

    protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
    {
        if (AllowDragOrdering)
        {
            DataGridView.HitTestInfo hti = this.HitTest(e.X, e.Y);

            if (hti.RowIndex != -1
             && hti.RowIndex != this.NewRowIndex
             && e.Button == MouseButtons.Left)
            {
                bDragging = true;
            }
        }

        base.OnMouseDown(e);
    }

    protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
    {
        if (bDragging && e.Button == MouseButtons.Left)
        {
            DataGridView.HitTestInfo newhti = this.HitTest(e.X, e.Y);
            if (hti != null && hti.RowIndex != newhti.RowIndex)
            {
                System.Diagnostics.Debug.WriteLine("invalidating " + hti.RowIndex.ToString());
                Invalidate();
            }
            hti = newhti;
            System.Diagnostics.Debug.WriteLine(string.Format("{0:000} {1}  ", hti.RowIndex, e.Location));

            Point clientPoint = this.PointToClient(e.Location);


            System.Diagnostics.Debug.WriteLine(e.Location + "  " + this.Bounds.Size);
            if (scrollTimer == null
            && ShouldScrollDown(e.Location))
            {
                //
                // enable the timer to scroll the screen
                //
                scrollTimer = new System.Threading.Timer(new System.Threading.TimerCallback(TimerScroll), 1, 0, 250);
            }
            if (scrollTimer == null
            && ShouldScrollUp(e.Location))
            {
                scrollTimer = new System.Threading.Timer(new System.Threading.TimerCallback(TimerScroll), -1, 0, 250);
            }

        }
        else
        {
            bDragging = false;
        }

        if (!(ShouldScrollUp(e.Location) || ShouldScrollDown(e.Location)))
        {
            StopAutoScrolling();
        }
        base.OnMouseMove(e);
    }

    bool ShouldScrollUp(Point location)
    {
        return location.Y > this.ColumnHeadersHeight
            && location.Y < this.ColumnHeadersHeight + 15
            && location.X >= 0
            && location.X <= this.Bounds.Width;
    }

    bool ShouldScrollDown(Point location)
    {
        return location.Y > this.Bounds.Height - 15
            && location.Y < this.Bounds.Height
            && location.X >= 0
            && location.X <= this.Bounds.Width;
    }

    void StopAutoScrolling()
    {
        if (scrollTimer != null)
        {
            //
            // disable the timer to scroll the screen
            // 
            scrollTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            scrollTimer = null;
        }
    }

    void TimerScroll(object state)
    {
        SetScrollBar((int)state);
    }

    bool scrolling = false;

    void SetScrollBar(int direction)
    {
        if (scrolling)
        {
            return;
        }
        if (this.InvokeRequired)
        {
            this.Invoke(new Action<int>(SetScrollBar), new object[] {direction});
        }
        else
        {
            scrolling = true;

            if (0 < direction)
            {
                if (this.FirstDisplayedScrollingRowIndex < this.Rows.Count - 1)
                {
                    this.FirstDisplayedScrollingRowIndex++;
                }
            }
            else
            {
                if (this.FirstDisplayedScrollingRowIndex > 0)
                {
                    this.FirstDisplayedScrollingRowIndex--;
                }
            }

            scrolling = false;
        }

    }



    protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
    {
        bDragging = false;
        HitTestInfo livehti = hti;
        hti = null;

        if (RowDropped != null
         && livehti != null
         && livehti.RowIndex != -1
         && this.CurrentRow.Index != livehti.RowIndex)
        {
            RowDropped(this, this.CurrentRow, this.Rows[livehti.RowIndex]);
        }
        StopAutoScrolling();

        Invalidate();
        base.OnMouseUp(e);
    }

    protected override void OnCellPainting(System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
    {
        if (bDragging && hti != null && hti.RowIndex != -1
         && e.RowIndex == hti.RowIndex)
        {
            //
            // draw the indicator
            //
            Pen p = new Pen(Color.FromArgb(0, 0, 215));
            p.Width = 4;
            e.Graphics.DrawLine(p, e.CellBounds.Left, e.CellBounds.Top, e.CellBounds.Right, e.CellBounds.Top);
        }

        base.OnCellPainting(e);
    }
}
1 голос
/ 02 апреля 2010

Спасибо за помощь с моей проблемой, возможно, я могу помочь вам с вашей.

С эта страница:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

//winuser.h constants
private const int WM_VSCROLL = 277; // Vertical scroll
private const int SB_LINEUP = 0;    // Scrolls one line up
private const int SB_LINEDOWN = 1;  // Scrolls one line down
private const int SB_ENDSCROLL = 8; // Ends the scrolling

//Call this when you want to scroll
private void ScrollGridview(int direction)
{
    SendMessage(Handle, WM_VSCROLL, (IntPtr)direction, VerticalScrollBar.Handle);
    SendMessage(Handle, WM_VSCROLL, (IntPtr)SB_ENDSCROLL, VerticalScrollBar.Handle);
}

(Второй SendMessage не кажется необходимым, но я включил его для хорошей меры)

Я написал элемент управления DataGridView, который включает в себя это решение gbogumil для автоматической прокрутки и правильно функционирующую подсветку OnPaint - вы можете найти его здесь .

Я хотел бы также указать этот элемент управления , который я только что нашел из другого потока. Это выглядит действительно красиво, но, к сожалению, это GPL, поэтому вы можете использовать его только для проектов GPL. Это делает все, что нам нужно, плюс намного больше, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...