views:

160

answers:

5

I have a gridview and, when a record is double-clicked, I want it to open up a new detail-view form for that particular record.

As an example, I have created a Customer class:

using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Collections;

namespace SyncTest
{
#region Customer Collection

public class CustomerCollection : BindingListView<Customer>
{
    public CustomerCollection() : base()
    {
    }

    public CustomerCollection(List<Customer> customers) : base(customers)
    {
    }

    public CustomerCollection(DataTable dt)
    {
        foreach (DataRow oRow in dt.Rows)
        {
            Customer c = new Customer(oRow);
            this.Add(c);
        }
    }
}

#endregion

public class Customer : INotifyPropertyChanged, IEditableObject, IDataErrorInfo
{
    private string _CustomerID;
    private string _CompanyName;
    private string _ContactName;
    private string _ContactTitle;
    private string _OldCustomerID;
    private string _OldCompanyName;
    private string _OldContactName;
    private string _OldContactTitle; 
    private bool _Editing;
    private string _Error = string.Empty;
    private EntityStateEnum _EntityState;
    private Hashtable _PropErrors = new Hashtable();

    public event PropertyChangedEventHandler PropertyChanged;

    private void FirePropertyChangeNotification(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

    public Customer()
    {
        this.EntityState = EntityStateEnum.Unchanged;
    }

    public Customer(DataRow dr)
    {
        //Populates the business object item from a data row
        this.CustomerID = dr["CustomerID"].ToString();
        this.CompanyName = dr["CompanyName"].ToString();
        this.ContactName = dr["ContactName"].ToString();
        this.ContactTitle = dr["ContactTitle"].ToString();

        this.EntityState = EntityStateEnum.Unchanged;
    }

    public string CustomerID
    {
        get
        {
            return _CustomerID;
        }
        set
        {
            _CustomerID = value;
            FirePropertyChangeNotification("CustomerID");
        }
    }

    public string CompanyName
    {
        get
        {
            return _CompanyName;
        }
        set
        {
            _CompanyName = value;
            FirePropertyChangeNotification("CompanyName");
        }
    }

    public string ContactName
    {
        get
        {
            return _ContactName;
        }
        set
        {
            _ContactName = value;
            FirePropertyChangeNotification("ContactName");
        }
    }

    public string ContactTitle
    {
        get
        {
            return _ContactTitle;
        }
        set
        {
            _ContactTitle = value;
            FirePropertyChangeNotification("ContactTitle");
        }
    }

    public Boolean IsDirty
    {
        get
        {
            return ((this.EntityState != EntityStateEnum.Unchanged) || (this.EntityState != EntityStateEnum.Deleted));
        }
    }

    public enum EntityStateEnum
    {
        Unchanged,
        Added,
        Deleted,
        Modified
    }

    void IEditableObject.BeginEdit()
    {
        if (!_Editing)
        {
            _OldCustomerID = _CustomerID;
            _OldCompanyName = _CompanyName;
            _OldContactName = _ContactName;
            _OldContactTitle = _ContactTitle;
        }
        this.EntityState = EntityStateEnum.Modified;
        _Editing = true;
    }

    void IEditableObject.CancelEdit()
    {
        if (_Editing)
        {
            _CustomerID = _OldCustomerID;
            _CompanyName = _OldCompanyName;
            _ContactName = _OldContactName;
            _ContactTitle = _OldContactTitle;
        }
        this.EntityState = EntityStateEnum.Unchanged;
        _Editing = false;
    }

    void IEditableObject.EndEdit()
    {
        _Editing = false;
    }

    public EntityStateEnum EntityState
    {
        get
        {
            return _EntityState;
        }
        set
        {
            _EntityState = value;
        }
    }

    string IDataErrorInfo.Error
    {
        get
        {
            return _Error;
        }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            return (string)_PropErrors[columnName];
        }
    }

    private void DataStateChanged(EntityStateEnum dataState, string propertyName)
    {
        //Raise the event
        if (PropertyChanged != null && propertyName != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        //If the state is deleted, mark it as deleted
        if (dataState == EntityStateEnum.Deleted)
        {
            this.EntityState = dataState;
        }
        if (this.EntityState == EntityStateEnum.Unchanged)
        {
            this.EntityState = dataState;
        }
    }
}

}

Here is my the code for the double-click event:

        private void customersDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
    {
        Customer oCustomer = (Customer)customersBindingSource.CurrencyManager.List[customersBindingSource.CurrencyManager.Position];
        CustomerForm oForm = new CustomerForm();
        oForm.NewCustomer = oCustomer;
        oForm.ShowDialog(this);

        oForm.Dispose();
        oForm = null;
    }

Unfortunately, when this code runs, I receive an InvalidCastException error stating "Unable to cast object to type 'System.Data.DataRowView' to type 'SyncTest.Customer'".

This error occurs on the very first line of that event:

Customer oCustomer = (Customer)customersBindingSource.CurrencyManager.List[customersBindingSource.CurrencyManager.Position];

What am I doing wrong?... and what can I do to fix this? Any help is greatly appreciated.

Thanks!


EDIT:

Here is how the data is populated:

    private void Form1_Load(object sender, EventArgs e)
    {
        // TODO: This line of code loads data into the 'northwindDataSet.Customers' table. You can move, or remove it, as needed.
        this.customersTableAdapter.Fill(this.northwindDataSet.Customers);
    }
A: 

When you get the invalid cast as you have described it is due to the object is not the type you think it should be.

You can avoid the exception by using the as keyword.

Customer oCustomer = (Customer)customersBindingSource.CurrencyManager.List[customersBindingSource.CurrencyManager.Position];

becomes

Customer oCustomer = customersBindingSource.CurrencyManager.List[customersBindingSource.CurrencyManager.Position] as Customer;

If it is an invalid cast then oCustomer will be null.

Now if you are still getting the null then the object from List is not a Customer object. I would use the debugger to determine what the object is and how you would go about casting it to your Cusomter object.

You will never be able to convert directly to the Customer object because your error is InvalidCastException error stating "Unable to cast object to type 'System.Data.DataRowView' to type 'SyncTest.Customer'". is giving you an DataRowView object. You need take the row and pull the values from the row.

David Basarab
A: 

How about using BindingSource.Current instead of CurrentManager? But from the looks of it, your data source is a DataSet.

Austin Salonen
+1  A: 

It looks like your object is of type System.Data.DataRowView, not Customer. Your code returns Dataset instead of objects that you are expecting. You need to modify the code that returns your objects.

Andrew Bezzub
A: 
private void customersDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
  DataGridView grid = (DataGridView) sender;
  Customer customer = (Customer) grid.Rows[e.RowIndex].DataBoundItem;
}

Checks removed for brevity

Catalin DICU
A: 
Customer oCustomer = (Customer) 
  ((DataRowView)customersBindingSource.Current).Row;
Trond