Linking the scroll bars of two controls
-
Hi all, I have two
DataGridView
s on my form with similar data in each. I'd like to view the same section of bothDataGridView
s at the same time. In other words, if the scroll bars in oneDataGridView
is scrolled, I want to set the scroll bars for the other one accordingly. I found this article which explains how to set scroll bars (using Interop) but I'm either doing something wrong or it's just not working forDataGridView
s: How to change scrollbars position in a multiline textbox[^] Based on the referenced article, this is block of code I currently have in the Scroll() event handler for but it does nothing:int orientation = 0;
switch (e.ScrollOrientation)
{
case ScrollOrientation.HorizontalScroll: orientation = 0; break;
case ScrollOrientation.VerticalScroll: orientation = 1; break;
}
SetScrollPos(dataGridView2.Handle, orientation, e.NewValue, true);
SendMessage(dataGridView2.Handle, EM_LINESCROLL, 0, e.NewValue);Could anyone help me out here please?
-
Hi all, I have two
DataGridView
s on my form with similar data in each. I'd like to view the same section of bothDataGridView
s at the same time. In other words, if the scroll bars in oneDataGridView
is scrolled, I want to set the scroll bars for the other one accordingly. I found this article which explains how to set scroll bars (using Interop) but I'm either doing something wrong or it's just not working forDataGridView
s: How to change scrollbars position in a multiline textbox[^] Based on the referenced article, this is block of code I currently have in the Scroll() event handler for but it does nothing:int orientation = 0;
switch (e.ScrollOrientation)
{
case ScrollOrientation.HorizontalScroll: orientation = 0; break;
case ScrollOrientation.VerticalScroll: orientation = 1; break;
}
SetScrollPos(dataGridView2.Handle, orientation, e.NewValue, true);
SendMessage(dataGridView2.Handle, EM_LINESCROLL, 0, e.NewValue);Could anyone help me out here please?
Hi, I haven't done this, however: 1. EM_LINESCROLL seems appropriate for a line-oriented Control, not for a Row/Column/Cell-oriented one. Not sure what would fit better. 2. I would try first without native code. I suggest you look into the
Scroll
event and theFirstDisplayedCell
,FirstDisplayedScrollingRowIndex
,FirstDisplayedScrollingColumnIndex
properties. You could get the row/column indexes from the one DGV and use those in scrolling the other DGV. :)Luc Pattyn [My Articles] Nil Volentibus Arduum
-
Hi all, I have two
DataGridView
s on my form with similar data in each. I'd like to view the same section of bothDataGridView
s at the same time. In other words, if the scroll bars in oneDataGridView
is scrolled, I want to set the scroll bars for the other one accordingly. I found this article which explains how to set scroll bars (using Interop) but I'm either doing something wrong or it's just not working forDataGridView
s: How to change scrollbars position in a multiline textbox[^] Based on the referenced article, this is block of code I currently have in the Scroll() event handler for but it does nothing:int orientation = 0;
switch (e.ScrollOrientation)
{
case ScrollOrientation.HorizontalScroll: orientation = 0; break;
case ScrollOrientation.VerticalScroll: orientation = 1; break;
}
SetScrollPos(dataGridView2.Handle, orientation, e.NewValue, true);
SendMessage(dataGridView2.Handle, EM_LINESCROLL, 0, e.NewValue);Could anyone help me out here please?
Have you tried: inheriting from DataGridView (gives you access to VerticalScrollBar), and putting some sort of synchronisation on your class?
class MyGrid : DataGridView {
public static void Link(IEnumerable<MyGrid> grids){
foreach(MyGrid grid in grids)
grid.VerticalScrollBar.Scroll += (s,e) => HandleScroll(grids, e.NewValue);}
static void HandleScroll(IEnumerable<MyGrid> grids, int value){
foreach(MyGrid grid in grids) grid.VerticalScrollBar.Value = value;
}
}And call it like:
var grids = List<MyGrid>();
grids.Add(myFirstGrid);
grids.Add(mySecondGrid);MyGrid.Link(grids);
... in your form's initialisation process. (Note: I haven't tried this, just going on the documentation.) Ed: I tried, and you do have to have the lists as type MyGrid, not DataGridView. So you will have to make the controls on your form MyGrids, too. Also, you might want to handle DataGridView.Scroll as well as the scrollbar's Scroll; I'm not sure when each one gets fired.
-
Hi, I haven't done this, however: 1. EM_LINESCROLL seems appropriate for a line-oriented Control, not for a Row/Column/Cell-oriented one. Not sure what would fit better. 2. I would try first without native code. I suggest you look into the
Scroll
event and theFirstDisplayedCell
,FirstDisplayedScrollingRowIndex
,FirstDisplayedScrollingColumnIndex
properties. You could get the row/column indexes from the one DGV and use those in scrolling the other DGV. :)Luc Pattyn [My Articles] Nil Volentibus Arduum
Thanks, but no, it doesn't quite solve my problem. 1. Yes, I also wondered about EM_LINESCROLL and I also wasn't sure what else to use or even how to go about finding out. 2. I know of the FirstDisplayedCell, FirstDisplayedScrollingRowIndex and FirstDisplayedScrollingColumnIndex properties but they only scroll the DataGridView to integral positions that coincide with the start of the referenced cell, row or column. Thanks though.
-
Have you tried: inheriting from DataGridView (gives you access to VerticalScrollBar), and putting some sort of synchronisation on your class?
class MyGrid : DataGridView {
public static void Link(IEnumerable<MyGrid> grids){
foreach(MyGrid grid in grids)
grid.VerticalScrollBar.Scroll += (s,e) => HandleScroll(grids, e.NewValue);}
static void HandleScroll(IEnumerable<MyGrid> grids, int value){
foreach(MyGrid grid in grids) grid.VerticalScrollBar.Value = value;
}
}And call it like:
var grids = List<MyGrid>();
grids.Add(myFirstGrid);
grids.Add(mySecondGrid);MyGrid.Link(grids);
... in your form's initialisation process. (Note: I haven't tried this, just going on the documentation.) Ed: I tried, and you do have to have the lists as type MyGrid, not DataGridView. So you will have to make the controls on your form MyGrids, too. Also, you might want to handle DataGridView.Scroll as well as the scrollbar's Scroll; I'm not sure when each one gets fired.
What a beautiful solution, thanks. It doesn't work 100% though. It only synchronises the scrollbars but not the actual position of the grid inside the gridview. Any idea why that would be? It seems that by setting MyGrid.VerticalScrollBar.Value, it only updates the position of the scrollbar but does nothing to the body of the grid.
-
What a beautiful solution, thanks. It doesn't work 100% though. It only synchronises the scrollbars but not the actual position of the grid inside the gridview. Any idea why that would be? It seems that by setting MyGrid.VerticalScrollBar.Value, it only updates the position of the scrollbar but does nothing to the body of the grid.
Ah damn, I thought that setting Value would make the grid scroll. I guess it is hooked to the Scroll property and I don't see any way of externally forcing a scrollbar to fire that. You could probably send it a WM_SCROLL but if you need to resort to P/Invoke then you might as well do that directly on the grid – I'm trying to turn up a managed solution. Another thing you can try using the same protected-uncovering hackery is to call grid.OnScroll (with a ScrollEventArgs preset to the offset you want). But I suspect all that will do is fire the DGV.Scroll event and not actually cause the visible region to change. You might have to resort to synchronising rows with FirstDisplayedRow, which isn't ideal.
-
Ah damn, I thought that setting Value would make the grid scroll. I guess it is hooked to the Scroll property and I don't see any way of externally forcing a scrollbar to fire that. You could probably send it a WM_SCROLL but if you need to resort to P/Invoke then you might as well do that directly on the grid – I'm trying to turn up a managed solution. Another thing you can try using the same protected-uncovering hackery is to call grid.OnScroll (with a ScrollEventArgs preset to the offset you want). But I suspect all that will do is fire the DGV.Scroll event and not actually cause the visible region to change. You might have to resort to synchronising rows with FirstDisplayedRow, which isn't ideal.
Yes, I'm pretty sure calling OnScroll will just fire the event but not update the actual gridview client area. I wouldn't mind resorting to synchronising the two grids based on FirstDisplayedScrollingRowIndex and FirstDisplayedScrollingColumnIndex if I had a way of forcing the grid to only scroll horizontally to integral values. In fact, for vertical scrolling, this method of syncing the two grids works perfectly. It's the horizontal scrolling that's a problem because the grid of which the scrollbar is moved can be scrolled to a position where it starts on a partial column, yet the linked grid will be scrolled to the start of that column. Do you know if there is a way I could enforce horizontal scrolling to also be limited to integral positions as is the case with vertical scrolling?
-
Yes, I'm pretty sure calling OnScroll will just fire the event but not update the actual gridview client area. I wouldn't mind resorting to synchronising the two grids based on FirstDisplayedScrollingRowIndex and FirstDisplayedScrollingColumnIndex if I had a way of forcing the grid to only scroll horizontally to integral values. In fact, for vertical scrolling, this method of syncing the two grids works perfectly. It's the horizontal scrolling that's a problem because the grid of which the scrollbar is moved can be scrolled to a position where it starts on a partial column, yet the linked grid will be scrolled to the start of that column. Do you know if there is a way I could enforce horizontal scrolling to also be limited to integral positions as is the case with vertical scrolling?
According to the documentation, DataGridView.HorizontalScrollOffset[^] is read/write. So you should be able to synchronise that without even needing to inherit from the DGV, as it's a public property. Why the vertical equivalent is read-only I don't understand. But that should work for horizontal scrolling (as long as you don't allow the user to mess with the column widths).
-
According to the documentation, DataGridView.HorizontalScrollOffset[^] is read/write. So you should be able to synchronise that without even needing to inherit from the DGV, as it's a public property. Why the vertical equivalent is read-only I don't understand. But that should work for horizontal scrolling (as long as you don't allow the user to mess with the column widths).