Scrolling a DataGridView

Hi,

I'v done a little C# WinFormApp with B2.
The App loads data to a BinddingSource via List<myClass>.
This BindingSource is bound to a DataGridView.

Everything works as expected, when I navigate via a BindingNavigator the DataGridView marks the selected row....
BUT: I can't find a way to scroll the selected row into the visual part of the DataGridView.
So I watch the selector going down - and must follow him wiht manual scrolling.

The things become worse, when I enter a number in the BindingNavigator.
Any row of the datagridview gets the selection - but how to make this visible.

There is a property -- Displayed - this shows (correct) false - but that is no help since I don't know how to scroll the thing.

There is no "EnsureVisible" like for a ListViewItem.

Does anyone know a solution

Regards

Manfred



Answer this question

Scrolling a DataGridView

  • Ehr

    Thanks a bunch Manfred for detailing this out. I've tested this out on latest bits and it looks like we have this issue fixed. I don't have a Beta2 build handy to see where the bug was at, but it doesn't repro. For now I'd continue to use your boolean flag.

    thanks!
    -mark
    Program Manager
    Microsoft
    This post is provided "as-is"

  • gabit7

    Hi,


    you could try playing with the VScrollBar in the DataGrid.

    VScrollBar v;
    for (int i =0; i < dg.Controls.Count; i++) {
       if (dg.ControlsIdea.GetType().ToString() == "VScrollBar") {
          v =  = dg.ControlsIdea;
          break;
       }
    }

    You could try to scrolldown the Scrollbar until the Displayed property of the DataGridRow is true...




    cheers,


    Paul June A. Domag


  • pawan_atl

    First off, we had made a bug fix post Beta2 so that setting the current cell correctly caused the grid to scroll. I was using this recent build to try it out.

    Second - Can you post more code or open a bug for your scenario. I want to investigate why it doesn't work and see if there is something we can do.

    Hope this helps!
    -mark
    Program Manager
    Microsoft
    This post is provided "as-is"


  • Ole Preisler - MSFT

    Hi Mark,

    as you see I do the thing with the "FirstDisplayScrollingRwo".
    But the thing with CurrentCell does not work correct.

    It has the same problems as my code had.
    To see how it fails try filling about twice as visible rows in a DGV.
    Add a handler for the CurrentChanged in the BindingSource.
    There use

    dataGridView1.CurrentCell=dataGridView1.Rows[ItemBindingSource.Position].Cells[0];

    to try it


    Start the app and use a Navigator and do the following:
    Enter a number - and watch how it works.
    Click on the selected row - than back to the navigator - another number
    STILL WORKS!
    Now stay in the navigator enter another number that needs scrolling.
    It does not work!!
    The cell is selected - but scrolling does not work. It works only imideatly after the DGV had the focus.

    Maybe you have the same problem than I Smile
    I encountered the following (with a handler for RowEnter of DGV):
    Assume your DGV has 5 visible rows.
    Row 1 is selected and visible the DGV has the focus.
    In the navigator I enter 20 - in the handler i get 20 for e.RowIndex (FINE!!)
    Now I drag down the scrollbar to lets say 100 and click that Row.
    What I get is e.RowIndex 20 (and if not handled) e.RowIndex 100
    So it looks like setting the focus (by clicking that a new row) fires a RowEnter for the current selected row.
    And if you handle this first one you will get the second with a wrong index!!
    It seems the control calculates the new row depending on what is visible and an offset.
    For an example: you have 5 rows visible.
    You select row 20 (with the mouse).
    Than you use the navigator to select row 2
    With row 1 is selected and visible as the first row you scroll down one page.
    Be sure only to use the scrollbar and do not click into the rows!!
    Now you are down and row 10 is the topmost visible.
    Now click row 13.
    If your handler does not take care you will get:
    a.) e.RowIndex==1 (you select this thing and scroll it back in)
    then
    b.) e.RowIndex==3 (since you clicked an offset of 3 rows)

    STRANGE Tongue Tied

    My code works now (tries to center the current row) and looks like this:



    private void dataGridView1_RowEnter(object sender, DataGridViewCellEventArgs e) {
       if (!dataGridView1.Rows[e.RowIndex].Displayed) {   //only if there is a need!
          
    if (e.RowIndex != dataGridView1.CurrentRow.Index) { //avoid useless setting if focus set -- makes problems
          // because 2 RowEnter events are fired - first for the current row (because of focus)
          // and one for the new row - but the new one is calculate by the mouseposition
          // so if we scroll first - a wrong row gets selected

          dataGridView1.FirstDisplayedScrollingRowIndex = (e.RowIndex -      m_nDisplayedRows / 2) >= 0 e.RowIndex - m_nDisplayedRows / 2 : 0;
          }
       }
    }

    Thanks for your help - maybe my investigations helps also a little

    Manfred


  • DLG007

    There are a few ways to scroll the DataGridView - First setting the CurrentCell property automatically scrolls the cell into view. You can also set the FirstDisplayScrollingRowIndex to scroll the grid manually.

    We had looked into an EnsureVisible but do not have the time to test it for this release.

    Hope these methods help!
    -mark
    Program Manager
    Microsoft
    This post is provided "as-is"

  • Therese

    Hi,

    since Pauls suggestion made me thinking about resolving it via "handmade code" I wrote a little thing which works. Not perfect - but better then not scrolling.
    First i declare a variable (m_nDisplayedRows  initialized with -1) for holding the number of displayed rows in the datagridview.
    With this I can scroll the "invisible row" into the middel of the DGV.

    Here is the code for the CurrentChanged event of the bound BindingSource.

    if (m_nDisplayedRows == -1) {
       bool bFoundDisplayed = false;
       int nFirst = 0;
       int nLast = 1;

       foreach (DataGridViewRow Row in dataGridView1.Rows) {
          if(!bFoundDisplayed) { //till now no displayed found!
             if(!Row.Displayed) { //not visilbe
                continue;
             }
             bFoundDisplayed =
    true;
             nFirst = Row.Index;
          }

          else {
             if (!Row.Displayed) {
                break;
             }
             nLast = Row.Index;
          }
       }
       m_nDisplayedRows = nLast - nFirst;
       }

    if (!dataGridView1.CurrentRow.Displayed) {
       dataGridView1.FirstDisplayedScrollingRowIndex = (dataGridView1.CurrentRow.Index-m_nDisplayedRows/2)>=0 dataGridView1.CurrentRow.Index-m_nDisplayedRows/2 : 0;
    }

    A littel more work than just call "EnsureVisible" - but it works Big Smile

    Cheers

    Manfred


  • khaleel

    Hi,

    I think I solved the problem!
    I have a handler for the BindigSource.CurrentChanged.

    This handler looks if a fiel (displayed in the DGV) is null.
    If so, it loads data to the field.
    If not - nothing is done!!

    When data is loaded the scrolling fails - if not it works as expected!

    So I placed the handling to the RowEnter event of the DGV - and now everything works fine.

    Conclusio: If I change the bound data in CurrentChanged of the bindig source I distrube the scrolling logic of the DGV.
    Positive: works now
    Negative: took me a lot of hours Tongue Tied

    Thanks for all your help

    Manfred

  • orit_itzhar

    Hi Mark,

    I made an App left everything default and added a Dataset.
    In this dataset I enter two columns C1 and C2 type Int32.
    Next I placed a DataGridView and a DataNavigator on the form.
    And I added a handler for CurrentChanged of the BindingNavigator.

    To simulate my relas world scenario - (where I load a huge BLOB field only if the row is selected) I assume that C2 is that "load if needed field".
    Funny thing - watch (and try) the comment in "FormLoad".


    public partial class Form1 : Form {
       
    private bool bLoading;
       
    public Form1() {
          InitializeComponent();
       }

       private void Form1_Load(object sender, EventArgs e) {
          DataSet1.DataTable1DataTable dT=(DataSet1.DataTable1DataTable)dataSet1.Tables[0];
          DataSet1.DataTable1Row dR;
       
          bLoading =
    true; //comment this line - and watch empty rows appearing :-)

          for (int nX = 0; nX < 20; nX++) {
             dR = dT.NewDataTable1Row();
             dR.C1 = nX;
             dR.C2 = 0;
             dT.Rows.Add(dR);
          }
          bLoading =
    false;
       }

       private void DataTable1BindingSource_CurrentChanged(object sender, EventArgs e) {
          if (!bLoading) {
             DataSet1.DataTable1Row dR = ((DataRowView)DataTable1BindingSource.Current).Row as DataSet1.DataTable1Row;
             if (dR != null) {
                if (dR.C2 == 0) {
                   dR.C2 = dR.C1;
                }
             } 
          }
       }
    }


     


    Cheers

    Manfred

  • Francisco Rivas

    Hi Paul,

    thanks for that snippet - pretty hard I think Smile
    Especialy when I think about the "EnsureVisible" in the "old Controls".

    I can't understand why such an important thing is missing in the "very best data control".
    But we are in beta - maybe that changes till RTM.

    Because we have perfect navigation controls, easy databing -- everything better than before - and than such a "step backward" from the old controls.

    Thanks again

    Manfred

  • Scrolling a DataGridView