Answered DataGridView: Finding a row in code

  • 2012년 7월 25일 수요일 오전 12:28
     
      코드 있음

    Visual Studio 2010 Pro

    SQL Server 2008 back end

    Using a Master/Detail form and bound datagridviews

    I am trying to "Find" a certain row if it exists in the DETAIL grid, witch is bound to a FOREIGN KEY in my dataset.

    This:

    int i = fKPurchaseOrderDetailPurchaseOrderBindingSource.Find("Production_No", myProdNo);
    if (i > -1)
    {
       fKPurchaseOrderDetailPurchaseOrderBindingSource.CurrencyManager.Position = i;
    }

    gives me THIS error:

    DataMember property 'Production_No' cannot be found on the DataSource.

    Here is a snap of my Dataset

    It's There, I swear!

    So tell me... what am I doing wrong?

    Just for debugging, How do I get a list of what CAN be "found on the datasource"?


    I'd rather live with false hope than with false despair.


    • 편집됨 Bryan Valencia 2012년 7월 25일 수요일 오전 12:35 added detail
    •  

모든 응답

  • 2012년 7월 25일 수요일 오전 7:48
     
     

    Hi, you were not precise, or do you wanna find a DataGridViewRow, or some value inside the row (the value of Product_No column)?

    But based on your code, you are trying to do something completely different.

    Give us more info, and please use some more.

    --

    But Find method seem to be Ok.


    Mitja

  • 2012년 7월 25일 수요일 오전 7:57
     
     

    You know, you try to be precise and somehow there is always room for improvement.

    I want to find the detail grid row that contains the production number that I have already collected in a search (that's the variable myProdNo).  Once I find the row, I'd like to move the cursor there (or maybe set the grid row background to a different color). 


    I'd rather live with false hope than with false despair.

  • 2012년 7월 25일 수요일 오전 8:10
     
      코드 있음

    Tell me, what if your DataSource type? Is it DataTable?

    But in any case, i would suggest you to do this with a different approach. Personally I would not use Find() method what so ever, but rather to do a loop over the dataGridView it self, and check that "Product_No" column. And if the number would be find (maybe even more of them in multiple rows), that/those row(s) would be selected (or colored differently).

    This is my suggestion:

    int myProdNo = 1; //some number you are looking for!
    int tempNo = 0;
    foreach(DataGridViewRow row in dataGridView1.Rows)
    {
        if(!row.IsNewRow)
        {
            tempNo = int.Parse(row.Cells["ProductNo"].Value.ToString()); 
            if(tempNo == myProdNo)
            {
                row.DefaultCellStyle.BackColor = Color.Black; //or any other color!
            }
        }
    }

    NOTE: I hope you have the "Product_No" column inisde datagridview control!


    Mitja

  • 2012년 7월 25일 수요일 오후 9:42
     
      코드 있음

    Actually if it's just the cell color, I was able to do this...

            private void OrderDetailsGrid_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
            {
                if (OrderDetailsGrid.Rows[e.RowIndex].Cells["DetailProductionNo"].Value.ToString() == myProdNo)
                {
                    OrderDetailsGrid.Rows[e.RowIndex].DefaultCellStyle.Font = new System.Drawing.Font(OrderDetailsGrid.Font, System.Drawing.FontStyle.Bold);
                }
            }


    I'd rather live with false hope than with false despair.

  • 2012년 7월 27일 금요일 오전 7:22
    중재자
     
      코드 있음

    Hi Bryan,

    You can search for the item by using property descriptor instead of the property name, so you can avoid the can't found DataMember property error.

    Try the code below.

    var v = fKPurchaseOrderDetailPurchaseOrderBindingSource.CurrencyManager.GetItemProperties();
    
                var vv = this.fKPurchaseOrderDetailPurchaseOrderBindingSource.Find(v["Production_No"], myProdNo);

    Best Regards,


    Bob Wu [MSFT]
    MSDN Community Support | Feedback to us

  • 2012년 7월 27일 금요일 오후 6:58
     
     
    Nope. it just gives a "capability not supported" error.

    I'd rather live with false hope than with false despair.

  • 2012년 7월 28일 토요일 오전 6:09
     
      코드 있음

    Hello, here is a thought. The code below works against a strong type DataSet using Microsoft NorthWind database, Categories table. All objects below, BindingSource and DataSet where dropped onto the form.

    In Form Load event

    Me.CategoriesTableAdapter.Fill(Me.NORTHWNDDataSet.Categories)

    For the search I use a hard coded variable, you already have a method I am guessing to get the ID to search with. If there where a chance the ID did not exists in the detail table you would check the result before setting the BindingSource Position. FindByCategoryID is a method (function) generated by Visual Studio.

    Dim KeyToFind As Integer = 4
    CategoriesBindingSource.Position = NORTHWNDDataSet.Categories.FindByCategoryID(KeyToFind).CategoryID - 1

    If the Find method does not exists we could position via the language extension below against the DataGridView which has a Bindingsource (same as above) that when setting the current cell positions the DataGridView which you can detect in the PositionChanged event of the BindingSource.

    Usage, argument 1 is the DataGridView ColumnName to search on, argument 2 is the value to find, argument 3 indicates a full or partial search. The last argument was tossed in to show you can get the row selected cell values.

    Dim Row As New DataGridViewRow
    If DataGridView1.Seek("CategoryNameDataGridViewTextBoxColumn", "Confections", False, Row) Then
        Console.WriteLine("[{0}]", Row.Cells(0).Value)
    End If

    The extension needs to be in a code module, not a class or the form.

    <System.Diagnostics.DebuggerStepThrough()> _
    <Runtime.CompilerServices.Extension()> _
    Public Function Seek(ByVal sender As DataGridView, ByVal ColumnName As String, ByVal Value As String, ByVal Part As Boolean, ByRef Row As DataGridViewRow) As Boolean
        Dim Located As Boolean = False
        If sender.Columns.Contains(ColumnName) Then
            If Part Then
                Row = (From Rows In sender.Rows.Cast(Of DataGridViewRow)() Where Rows.Cells(ColumnName).Value.ToString().ToUpper.Contains(Value.ToUpper)).FirstOrDefault
            Else
                Row = (From Rows In sender.Rows.Cast(Of DataGridViewRow)() Where Rows.Cells(ColumnName).Value.ToString().ToUpper = Value.ToUpper).FirstOrDefault
            End If
            If Not IsNothing(Row) Then
                If sender.CurrentCell.RowIndex <> Row.Index Then
                    sender.CurrentCell = sender(0, Row.Index)
                End If
                Located = True
            End If
            Return Located
        Else
            Throw New Exception("Column '" & ColumnName & "' not contained in this DataGridView")
        End If
    End Function

    Alternate still using the above we can get data from the current row in the BindingSource by casting it as an DataRowView. In this case the last argument of the Seek method is not needed and the extension would be as below

    Dim Row As New DataGridViewRow
    If DataGridView1.Seek("CategoryNameDataGridViewTextBoxColumn", "Confections", False, Row) Then
        Console.WriteLine(CType(CategoriesBindingSource.Current, DataRowView).Item("Categoryid").ToString)
    End If

    Modified

            If DataGridView1.Seek("CategoryNameDataGridViewTextBoxColumn", "Confections", False) Then
                Console.WriteLine(CType(CategoriesBindingSource.Current, DataRowView).Item("Categoryid").ToString)
            End If
    <System.Diagnostics.DebuggerStepThrough()> _
    <Runtime.CompilerServices.Extension()> _
    Public Function Seek(ByVal sender As DataGridView, ByVal ColumnName As String, ByVal Value As String, ByVal Part As Boolean) As Boolean
        Dim Row As New DataGridViewRow
        Dim Located As Boolean = False
        If sender.Columns.Contains(ColumnName) Then
            If Part Then
                Row = (From Rows In sender.Rows.Cast(Of DataGridViewRow)() Where Rows.Cells(ColumnName).Value.ToString().ToUpper.Contains(Value.ToUpper)).FirstOrDefault
            Else
                Row = (From Rows In sender.Rows.Cast(Of DataGridViewRow)() Where Rows.Cells(ColumnName).Value.ToString().ToUpper = Value.ToUpper).FirstOrDefault
            End If
            If Not IsNothing(Row) Then
                If sender.CurrentCell.RowIndex <> Row.Index Then
                    sender.CurrentCell = sender(0, Row.Index)
                End If
                Located = True
            End If
            Return Located
        Else
            Throw New Exception("Column '" & ColumnName & "' not contained in this DataGridView")
        End If
    End Function



    KSG

  • 2012년 7월 28일 토요일 오후 4:26
     
     

    Well I'll have to translate all this into C#, but I get the drift.

    It seems needlessly complicated for what should be included functionality.  I am becoming more and more unimpressed with the DatagridView.


    I'd rather live with false hope than with false despair.

  • 2012년 7월 28일 토요일 오후 6:38
     
     답변됨 코드 있음

    Well I'll have to translate all this into C#, but I get the drift.

    It seems needlessly complicated for what should be included functionality.  I am becoming more and more unimpressed with the DatagridView.


    I'd rather live with false hope than with false despair.

    I will not address being unimpressed with the DataGridView other than saying I have always found a solution for my needs. In regards to It seems needlessly complicated you can slim down the code.

    Keeping with using the code as a language extension

    if (DataGridView1.Seek("CategoryNameDataGridViewTextBoxColumn", "Confections"))
    {
    	Console.WriteLine(((DataRowView)CategoriesBindingSource.Current)["Categoryid"].ToString());
    }


    [System.Diagnostics.DebuggerStepThrough(), Runtime.CompilerServices.Extension()]
    public bool Seek(DataGridView sender, string ColumnName, string Value)
    {
    	bool Located = false;
    	var Row = (
    			from Rows in sender.Rows.Cast<DataGridViewRow>()
    			where Rows.Cells(ColumnName).Value.ToString().ToUpper() == Value.ToUpper()).FirstOrDefault
    		select Rows;
    	if (Row != null)
    	{
    		sender.CurrentCell = sender[0, Row.Index];
    		Located = true;
    	}
    	return Located;
    }

    Lets say you know at least one row exists

    DataGridView1.CurrentCell = DataGridView1(0, (
    			from Rows in DataGridView1.Rows.Cast<DataGridViewRow>()
    			where Rows.Cells("CategoryNameDataGridViewTextBoxColumn").Value.ToString().ToUpper() == ValueToFind).FirstOrDefault.Index)
    	select Rows;


    KSG

  • 2012년 7월 31일 화요일 오전 10:48
    중재자
     
     답변됨
    Nope. it just gives a "capability not supported" error.

    I'd rather live with false hope than with false despair.

    Hi Bryan,

    My solution works great on my side and I'm not sure what is going on on your side.

    Could you please tell me which line throw the error message and post both the code and exact error message here?

    Could you please tell us more details about your application, such as the way you set the datasource and where the data come from?

    Anyway, here is my sample, you should check it out.

    Best Regards,


    Bob Wu [MSFT]
    MSDN Community Support | Feedback to us