简体   繁体   中英

ComboBox setting a value C#

I have a tough one for today. I am creating an app in Windows Forms using C#, and I am supposed to make an app that shows every order with its status, date and full price. That is all taken care of. The second form is meant to be order details, where I am supposed to have OrderID, ProductName inside of a combobox, UnitPrice and Quantity columns. I have managed to create all of them, set their values through SQL using Dapper, but I am having a hard time getting the combobox to display the value of ProductID.

To simplify: I want the combobox to show the name of the product with the ProductID that is matching to the one given in the order details. If I change the Product inside of combobox, I need it to take the combobox ProductID value and change it in Order Details. If the order is a new one with no details, it should set it by default for the ProductID to be 1.

The combobox is inside of a DataGridView that is using a list of order details created by Dapper. Everything else works like a charm, I am just having a lot of trouble with the combobox.

Here is some code, I will add more if needed:

This is the code for the combobox itself

private void fillcombobox()
        {
            DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
            combo.HeaderText = "ProductName";
            DataAccess dt = new DataAccess();
            products = dt.GetAllProducts();
            combo.DataSource = products;
            combo.DisplayMember = "ProductName";
            combo.ValueMember = "ProductID";
            orderdetailsGridView.Columns.Add(combo);
            combo.DisplayIndex = 0;
        }

Here is the OrderDetails class

public class OrderDetails
    {
        public int OrderID { get; set; }
        public int ProductID { get; set; }
        public decimal UnitPrice { get; set; }
        public int Quantity { get; set; }
    }

Here is the Product class

public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public decimal UnitPrice { get; set; }
        public int UnitsInStock { get; set; }
    }

Here is the query for the GetAllProducts

public List<Product> GetAllProducts()
        {
            using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(Helper.CnnVal("ShopDB")))
            {
                var output = connection.Query<Product>("select * from Products").ToList();
                return output;
            }
        }

在此处输入图片说明

After you set the data source for the combo you can attach yourself to the row added event of the orderdetailsGridView. In the event listener you can set the value of the combo column.

Attach to event

orderdetailsGridView.RowsAdded += DataGridView_RowsAdded;

Event listener can then go something like this:

     private void DataGridView_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
    {
        ((DataGridViewComboBoxCell)((DataGridView)sender).Rows[e.RowIndex].Cells["ProductName"]).Value =
            ((List<OrderDetails>)dataGridView1.DataSource)[e.RowIndex].ProductID;

    }

Since you are just doing products from your .Query class, just update your class structure to have a read-only property (having only a getter) that returns the formatted value for presentation purposes only in your combobox.

public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public decimal UnitPrice { get; set; }
        public int UnitsInStock { get; set; }
        public string ShowProductAndId 
           { get { return ProductName + " (" + ProductID + ")"; } }

    }

Then, set your display value to the new property "ShowProductAndId".

CLARIFICATION PLEASE

It appears we are not communicating well. You are asking about the product ID, which is what the value member will have (Product ID), but the Display member shows the actual product name. If this is a detail screen for a given order and you are listing the items someone ordered, I would expect something different for your query based on the single Order # being looked into. I would grab both the detail line item from the order detail AND the product ID as reference and its product name. Use an OrderDetail class that has all the parts actually ordered. Such a query might be

select
      OD.*,
      P.ProductName
   from
      OrderDetail OD
         JOIN Product P
            on OD.ProductID = P.ProductID
   where
      OD.OrderID = @selectedOrderToGetDetailsFor

Then, I would have your ShowOrderDetail be derived from your OrderDetail so you can tack-on the now expected product name as part of its result, something like below will get all properties of your NORMAL OrderDetail, but also include the Product name at the same time as a result set from the query above.

public class ShowOrderDetail : OrderDetail
{
   public string ProductName { get; set; }
}

Then, you could have the Order Details combo reference the ProductName from this class and not the ALL PRODUCTS.

Not necesssarily a great design plan. Dont know why you might have an order of 5 widgets, product ID = 3, then let the user see the line and let them change it to 5 somethingElse, product ID = 17. Doesn't make sense. But you COULD just have the Product Name as shown on the row since you now have it available as the result set and the user would not have the option to change the ordered item.

FINAL COMMENTS (hopeful?)

So, now I see what you have with your image. You basically need TWO bindings. One for the source of records to display, but the SELECTED VALUE (ID) needs to be bound to the ID key from the records in your data. It has been quite a while since I did C# Windows Forms and was not doing that much before I got into C#/WPF, so my bindings there are not as strong. I can try to play around with it some, but cant today.

However, take a look here . This other answer shows WinForms binding in code, similar to what you are doing to prepare your combobox. But you probably want to add an additional binding to the source that your selected detail record is and ITS product ID for the refresh.

So, the binding of the combobox would have TWO sources. The primary you already have for the list, but a second for the selected value binding to be bound to the list of details that the data grid of all items on the order, and to the PATH of the ProductID on that order detail record.

Look at how they are creating a "BindingSource", and setting that to the list. In your case, you want to point to your order details list. But then, the data member/path you want is the "ProductID" as it is on the detail record.

Hope I could help you more, but this SHOULD help push you to what you need.

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