How do I programmatically scroll a winforms datagr

2019-01-12 04:01发布

问题:

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 also 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

回答1:

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.



回答2:

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); 


回答3:

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.



回答4:

dgv.FirstDisplayedScrollingRowIndex = dgv.RowCount - 1;


回答5:

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.