开发者

How do I programmatically scroll a winforms datagridview control?

I'm implementing some drag drop features in one my controls inheriting from a datagridview. Basically I'm dragging a row from somewhere in the DGV and dropping it somewhere else, reordering the rows. I've run into a problem though. If the DGV is too large such that there's a scrollbar, how can I have the DGV scroll up or down while the user is in the middle of a dragdrop?

I know how to get the current mouse position and a开发者_运维百科lso get the position of the dgv rectangle and such. So, I can easily find out if i'm in the top or bottom half of the rectangle... I just need a way to programmatically scroll the dgv. I'd prefer if I don't have to keep changing the selected cell to do this.

Any suggestions?

Thanks

Isaac


Well, since this is a datagridview... Sorry for the 'winforms' in the question... but I could just do this.. scrolling up or down one row.

Scroll up:

this.FirstDisplayedScrollingRowIndex = this.FirstDisplayedScrollingRowIndex - 1

Scroll Down:

this.FirstDisplayedScrollingRowIndex = this.FirstDisplayedScrollingRowIndex + 1;

You've gotta make sure to check that the numbers don't go out of bounds though.


you can do this by setting HorizontalScrollingOffset / VerticalScrollingOffset of the DataGridView

to set HorizontalScrollingOffset

dataGridView1.HorizontalScrollingOffset = dataGridView1.HorizontalScrollingOffset + 10;

check

DataGridView.HorizontalScrollingOffset Property

and

for VerticalScrollingOffset you can use Reflection

include namespace System.Reflection

PropertyInfo verticalOffset = dataGridView1.GetType().GetProperty("VerticalOffset", BindingFlags.NonPublic | BindingFlags.Instance);
            verticalOffset.SetValue(this.dataGridView1, 10, null); 


dgv.FirstDisplayedScrollingRowIndex = dgv.RowCount - 1;


You may do that using WinAPI by sending message to the control telling it to scroll up or down.

Here is the code, I hope it helps:

private const int WM_SCROLL = 276; // Horizontal scroll
private const int WM_VSCROLL = 277; // Vertical scroll
private const int SB_LINEUP = 0; // Scrolls one line up
private const int SB_LINELEFT = 0;// Scrolls one cell left
private const int SB_LINEDOWN = 1; // Scrolls one line down
private const int SB_LINERIGHT = 1;// Scrolls one cell right
private const int SB_PAGEUP = 2; // Scrolls one page up
private const int SB_PAGELEFT = 2;// Scrolls one page left
private const int SB_PAGEDOWN = 3; // Scrolls one page down
private const int SB_PAGERIGTH = 3; // Scrolls one page right
private const int SB_PAGETOP = 6; // Scrolls to the upper left
private const int SB_LEFT = 6; // Scrolls to the left
private const int SB_PAGEBOTTOM = 7; // Scrolls to the upper right
private const int SB_RIGHT = 7; // Scrolls to the right
private const int SB_ENDSCROLL = 8; // Ends scroll

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

Now assuming you have a textbox control on your form. You can move it with:

SendMessage(textBox1.Handle,WM_VSCROLL,(IntPtr)SB_PAGEUP,IntPtr.Zero); //ScrollUp
SendMessage(textBox1.Handle,WM_VSCROLL,(IntPtr)SB_PAGEDOWN,IntPtr.Zero); //ScrollDown

If that classic general solution doesn't work for you. You may want to look at FirstDisplayedScrollingRowIndex Property and change it regarding your mouse position during dragging.


You need to implement the DragOver event. Check if the mouse is located close to the top or the bottom of the control (use PointToClient). When it is, enable a timer with an interval of ~200 msec. In the Tick event handler scroll the DGV by a row. Disable the timer when the mouse isn't close and after DoDragDrop returns. The user can now easily and intuitively scroll the grid just be hovering near the ends.


Answer using MaxEcho's answer as a base. You can override the OnScroll event of the DataGridView. The eventArgs in this method contain the first visible line number. You can pass this line number to the other DataGridView, and set the FirstDisplayedScrollRowIndex to cause it to scroll to that position.

The only issue is somewhat cosmetic, if you scroll quite fast, the second datagridview pauses updating/animating and blinks to the active line once your scrolling slows.

class DGVSubclass : DataGridView
{    

    public Action<ScrollEventArgs> delOnScroll;
    ....

    protected override void OnScroll(ScrollEventArgs e)
    {
        base.OnScroll(e);


        if (e.ScrollOrientation == ScrollOrientation.VerticalScroll && 
            delOnScroll != null)
            delOnScroll.Invoke(e);

    }

    public void setSrcoll(ScrollEventArgs e)
    {
        //ScrollEventArgs.NewValue is a line number
        this.FirstDisplayedScrollingRowIndex = e.NewValue;
    }

    public void bindScroll(DGV3_Broker dgv)
    {
        delOnScroll = dgv.setSrcoll;          
    }
}

dgvTwo.bindScroll(dgvOne);  //DGVTwo Scrollbar controls both, 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜