简体   繁体   中英

C# Showing Data in DatagridView?

This is my Form 1 在此处输入图像描述

When I click on the last row it shows data on the second grid control, Now I Want to Show this Data on the following Form (form 2 (Form with Purchase Written on Orange Color)) datagridview How can I do this.

在此处输入图像描述

        table.Columns.Add("Item Name", Type.GetType("System.String"));
        table.Columns.Add("Main Qty", Type.GetType("System.Decimal"));
        table.Columns.Add("Price", Type.GetType("System.Decimal"));
        table.Columns.Add("Per", Type.GetType("System.String"));
        table.Columns.Add("Basic Amount", Type.GetType("System.Decimal"));
        table.Columns.Add("Dis Amount", Type.GetType("System.Decimal"));
        table.Columns.Add("Dis Percentage", Type.GetType("System.Decimal"));
        table.Columns.Add("Tax Amount", Type.GetType("System.Decimal"));
        table.Columns.Add("Net Value", Type.GetType("System.Decimal"));
        dataGridView1.DataSource = table;

Above is the Form Load of (form 2)

And Below is the RowClick of Form 1

 private void gridView1_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e)
    {

        try
        {
            FRM_Purchase frm = new FRM_Purchase();

            
           
            var ctx = new BizPlusEntities();
            int GettingIdForShowing = (int)gridView1.GetRowCellValue(e.RowHandle, "PurchaseID");
         
            var GettinginToDatabase = ctx.Purchases.Where(x => x.PurchaseID == GettingIdForShowing).ToList();
            foreach (var item in GettinginToDatabase)
            {
                frm.txtPartyName.Text = item.PartyName;
                frm.txtDate.Text = item.Date.ToString();
                frm.txtTerms.Text = item.Terms;
                frm.txtSeries.Text = item.Series;
                frm.txtDueDate.Text = item.DueDate.ToString();
                frm.txtPinvoice.Text = item.Pinvoice.ToString();
                UniqueIdentifier = item.UniquePurchaseNumber;
                string SelectingUniqueIdentfier = ctx.Purchases.SingleOrDefault(x => x.PurchaseID == item.PurchaseID)?.UniquePurchaseNumber ?? "Nulled";

                var GettingInItems = ctx.ItemPurchaseDatas.Where(x => x.UniquePurchaseNumber == SelectingUniqueIdentfier).ToList();
                foreach (var Sam in GettingInItems)
                {
                    TItemName = Sam.ItemName;
                    TMainQty = Sam.MainQty ?? 0;
                    TPrice = Sam.Price ?? 0;
                    TPer = Sam.Per;
                    TBasicAmount = Sam.BasicAmount ?? 0;
                    TDisAmt = Sam.DisAmount ?? 0;
                    TDisP = Sam.DecimalPercentage ?? 0;
                    TTaxAmount = Sam.Gst ?? 0;
                    TTotalAmount = Sam.TotalAmount ?? 0;

                }


                frm.Show();
            }
        }
        catch (Exception)
        {

            throw;
        }
        
    }

The problem is When I do frm.Table.Rows.Add(TItem,TMainQty...) on Form1 it shows input array is longer than the number of columns in this table and when I create a new column it says the column already exists.

My advice would be to separate your data from the way that the data is displayed. Apart from that this makes it easier to unit test your data handling, it gives the displayer of the data the freedom to change how this data is being displayed.

In WPF this separation of model and view is almost forced, in Winforms you really have to pay attention otherwise you mix your data handling with the way that it is displayed, making it hard to change this.

In your case: should Form1 care about how the data is displayed in Form2, should it know that Form2 uses a DataGridView? Or should Form1 only care about what data is displayed in Form2, not in what format?

A proper interface with Form2 would be, that other Forms tell what data should be displayed, and if the data can be changed, that the other Form can ask afterwards the value of the data. Something like this:

private void ShowForm2()
{
    var dataToShow = this.FetchDataToShow();
    using (var dlg = new Form2())
    {
        dlg.Data = dataToShow;
        var dlgResult = dlg.ShowDialog(this);
        if (dlgResult == DialogResult.OK)
        {
            var dataToProcess = dlg.Data;
            this.ProcessData(dataToProcess);
        }
    }
}

This way, you only tell Form2 what data to show, other forms don't really care about how Form2 shows its data. This gives Form2 the freedom to change how the data is displayed. Every user of this Form will have the same human interface.

By the way: did you notice that I also separated where Form1 gets the data for Form2 from and where it stores the results? This procedure also does not care about how the data is displayed in Form1, and gives you the freedom to change Form1, without having to change this procedure.

Use Databinding

It is usually way easier to use DataBinding to handle the rows in a DataGridView than to access the rows and the cells of the DataGridView directly.

To use databinding, your columns need to know which property of your Class should be displayed in this column. This is usually done in visual studio designer.

In your case, it seems that the DataGridView of Form2 needs to show ItemPurchaseDatas : every Row in the DataGridView will show several properties of one ItemPurchaseData . Using visual studio designer you will have added columns, and in every column you select the name of the property that needs to be displayed in that column:

DataGridView dataGridView1 = new DataGridView();
DataGridViewColumn columnName = new DataGridViewColumn();
columName.HeaderText = "Item Name";
columName.DataPropertyName = nameof(ItemPurchaseData.Name);
...
DataGridViewColumn columnPrice = new DataGridViewColumn();
columnPrice.HeaderText = "Price";
columnPrice.DataPropertyName = nameof(ItemPurchaseData.Price);
...

We earlier saw that the dialog had a property Data, that contains the data to be shown. The form needs a method to extract the ItemPurchaseDatas that must be shown in the DataGridView:

public IEnumerable<ItemPurchaseData> GetInitialItemPurchaseDatas()
{
    // TODO: use property Data to extract the ItemPurchaseDatas that must be shown
    // in the DataGridView
}

Now all you have to do is on the event handler of FormLoad, get the data and put it in the DataSource of dataGridView1:

private void OnFormLoading(object sender, ...)
{
    List<ItemPurchaseData> itemPurchaseDatas = GetInitialItemPurchaseDatas().ToList();
    this.dataGridView1.DataSource = itemPurchaseDatas;
}

This is enough to show the data. However, it will be readonly: any changes that the operator makes: edits, addition of rows, removal of rows etc, are not reflected in itemPurchaseDatas. If you want that, you need an object that implements IBindingList like BindingList<T> .

If you want to know the changes that the operator made, it is usually wise to add the following methods:

private BindingList<ItemPurchaseData> DisplayedData
{
    get => (BindingList<ItemPurchaseData>)this.dataGridView1.DataSource;
    set => this.dataGridView1.DataSource = value;
}

Now every change that the operator makes to the displayed data: add / remove rows, change cells, etc are reflected in property DisplayedData. Again, the display of the data is separated from the data itself: If the operator changes the looks of how the data is displayed, sorting the rows, rearranging the columns has no influence on the DisplayedData.

If you regularly have to handle SelectedRows, consider to add the following properties:

private ItemPurchaseData CurrentItemPurchaseData =>
    (ItemPurchaseData)this.dataGridView1.CurrentRow?.DataBoundItem;

private IEnumerable<ItemPurchaseData> SelectedItemPurchaseData => 
    this.dataGridView1.DataSource.SelectedRows.Cast<DataGridViewRow>()
        .Select(row => row.DataBoundItem)
        .Cast<ItemPurchaseData>();
    

Usage: on form loading displaying the data in the DataGridView and after a button press process the edited data:

private void OnFormLoading(object sender, ...)
{
    IEnumerable<ItemPurchaseData> itemPurchaseDatas = GetInitialItemPurchaseDatas();
    this.DisplayedData = new BindingList<ItemPurchaseData>(itemPurchaseDatas.ToList());
}

private void OnButtonOk_Clicked(object sender, ...)
{
    ICollection<ItemPurchaseData> editedData = this.DisplayedData;
    // if needed: check which items are changed
    this.ProcessChangedData(editedData);
}

Again: due to the separation of view and model, the code in the view are one-liners

If you only want to Display the data, it is

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM