Home > OS >  Copy data from Grid View to another (is there a better way)
Copy data from Grid View to another (is there a better way)

Time:12-11

I have three Grid View
Grid View 1 contains these columns
IdProject ;IdItem ;Length ;Quantity

Grid View 2 contains these columns
IdInventory ;IdItem ;Length ;QuantityAvailable

Grid View 3 contains these columns
IdProject ;IdInventory ;IdItem ;Length ;ReservedQuantity ;UnavailableQuantity

The operation goes this way:
I compare (IdItem, Length, Quantity) from Grid View1 with Grid View2 If there is a match, I have two options:

  1. Quantity <= QuantityAvailable
    I add a row to Grid View3 (ReservedQuantity= Quantity and UnavailableQuantity=0)
  2. Quantity > QuantityAvailable
    I have two options:
    a- Grid View2: the matched row is not the last
    I add a row to Grid View3 (ReservedQuantity= QuantityAvailable and UnavailableQuantity=0) and continue to the next matched row
    b- Grid View2: the matched/ unmatched row is the last
    I add a row to Grid View3 (ReservedQuantity= QuantityAvailable and UnavailableQuantity= Quantity-Sum(ReservedQuantity))

I am used to using this code

        int[] selectedRows = gridView1.GetSelectedRows();
    for (int i = 0; i < selectedRows.Length; i  )
    {
        DataRow rowGridView1 = (gridView1.GetRow(selectedRows[i]) as DataRowView).Row;
        for (int j = 0; j < gridView2.RowCount; j  )
        {
                //check for comparison
                //add rows
        }
    }

CodePudding user response:

People who are new to DataGridViews tend to fiddle directly with the cells of the DataGridView, although it is way more easy to use the DataSource.

You wrote: The operation goes this way: I compare (IdItem, Length, Quantity) from Grid View1 with Grid View2.

Alas, Grid View1 doesn't have an (IdItem, Length, Quantity). However every row in this DataGridView has. I assume you meant to compare the rows in the Dgv

I think you meant to say, that you compare row 0 from Dgv1 with row 0 from Dgv2 and depending on the values you create row 0 from Dgv3. Similiarly you do this for all rows.

Apparently Dgv1 shows a sequence of similar items. I haven't got a clue what they are, so let's say, they are items of class A. This class is similar to the following:

class A
{
    public int IdProject {get; set;}
    public int IdItem {get; set;}
    public decimal Length {get; set;}
    public int Quantity {get; set;}
}

Similarly, Dgv2 shows items of class B:

class B
{
    public int IdInventory {get; set;}
    public int IdItem {get; set;}
    public decimal Length {get; set;}
    public int QuantityAvailable {get; set;}
}

And Dgv3 shows class C:

class C
{
    public int IdProject {get; set;}
    public int IdInventory {get; set;}
    public int IdItem {get; set;}
    public decimal Length {get; set;}
    public int ReservedQuantity {get; set;}
    public int UnavailableQuantity {get; set;}
}

It might be that your classes has several other properties, or other identifiers or types, but you get the gist.

Using visual studio designer you've added the three DataGridViews and the columns. In the constructor you can mention which column should show which property.

For this we use property DataGridViewColumn.DataPropertyName

// constructor
public MyForm()
{
    InitializeComponent();

    // Dgv1 shows properties of class A
    dgv1ColumnIdProject.DataPropertyName = nameof(A.IdProject);
    dgv1ColumnIdItem.DataPropertyName = nameof(A.IdItem);
    dgv1ColumnLength.DataPropertyName = nameof(A.Length);
    dgv1ColumnQuantity.DataPropertyName = nameof(B.Length);

    // Dgv2 shows properties of class B
    dgv2ColumnIdInventory.DataPropertyName = nameof(B.IdInventory);
    ... // etc also Dgv3 and class C
}

Somewhere you have methods to fetch the data that should be shown in Dgv1 and Dgv2:

(As is plural of A; Bs is plural of B, etc)

private IEnumerable<A> FetchAsToDisplay() {...}
private IEnumerable<B> FetchBsToDisplay() {...}

To fill the DataGridViews and to fetch the items in the DataGridVies create the following properties:

private BindingList<A> DisplayedAs
{
    get => (BindingList<A>)this.Dgv1.DataSource;
    set => this.Dgv1.DataSource = value;
}

private BindingList<B> DisplayedBs
{
    get => (BindingList<B>)this.Dgv2.DataSource;
    set => this.Dgv2.DataSource = value;
}

private BindingList<C> DisplayedCs
{
    get => (BindingList<C>)this.Dgv3.DataSource;
    set => this.Dgv3.DataSource = value;
}

Now to fill Dgv1 and Dgv2, with their initial values, do the following:

IEnumerable<A> asToDisplay = this.FetchAsToDisplay();
this.DisplayedAs = new BindingList<A>(asToDisplay.ToList());

IEnumerable<B> bsToDisplay = this.FetchBsToDisplay();
this.DisplayedBs = new BindingList<B>(bsToDisplay.ToList());

To calculate what should be in Dgv3, you can reuse asToDisplay and bsToDisplay, or if you have to do this later, for instance after clicking button OK:

private void OnButtonOk_Clicked(object sender, ...)
{
    ICollection<A> displayedAs = this.DisplayedAs;
    ICollection<B> displayedBs = this.DisplayedBs;

    IEnumerable<C> csToDisplay = this.CreateCsToDisplay(displayedAs, displayedBs);
    this.DisplayedCs = new BindingList(csToDisplay.ToList();
}

CreateCsToDisplay (TODO: invent a better name) is the procedure that decides what should be displayed, according to the two options you defined.

private IEnumerable<C> CreateCsToDisplay(IEnumerable<A> as, IEnumerable<B> bs)
{
    // assume Dgv1 and Dgv2 has the same number of rows,
    // so sequence as has the same number of elements as sequence bs
    // use ZIP to combine A and B. For every [a,b] combination create a C:
    return as.Zip(bs, (a, b) => this.CreateC(a, b);
}

private C CreateC(A a, B b)
{
     // use the conditions you defined
     if (a.Quantity < b.QuantityAvailable)
     {
         return new C
         {
             ReservedQuantity = a.Quantity,
             UnavailableQuantity = 0,
         };
     }
     else
     {
         return new C ... etc, see your specification
     }
}

Summary

By using the DataSource and a BindingList, you don't have to fiddle with the Rows and the Cells anymore, you can interpret the Rows as a sequence of similar items. The rows are accessed using properties like DisplayedAs. Get and Set the displayed items is now a piece of cake: just use the properties.

To calculate how to create one C from one [A, B] combination, we created one method CreateC. This method hides your specification.

Similarly we had one method that creates a sequence of Cs from sequences of As and Bs: CreateCsToDisplay. This method also hides how the Cs are created.

  • Related