I am trying to display my List in a ListView using a GridView. I am using dynamic binding as my list view changes. it's gridview for other purposes.
I have already used similar code twice and had no issues. I have checked every variable using a debugger and executed the code step by step and everything seemed normal.
// the code of the function
public void loadPairsIntoListView(object sender, RunWorkerCompletedEventArgs args)
{
XmlComparator xComp = XmlComparator.getInstance();
List<ComparePair> listOfPairs = xComp.getListOfPairs();
multiCompareListOfCompared.ItemsSource = listOfPairs;
multiCompareModelLabel.Content = listOfPairs[0].model.trueName + " " + listOfPairs[0].model.envName.ToUpper();
GridView myGridView = new GridView();
myGridView.ColumnHeaderToolTip = "Objet recap";
GridViewColumn gvc1 = new GridViewColumn();
gvc1.DisplayMemberBinding = new Binding("compared.trueName");
gvc1.Header = "nom";
gvc1.Width = 100;
myGridView.Columns.Add(gvc1);
GridViewColumn gvc2 = new GridViewColumn();
gvc2.DisplayMemberBinding = new Binding("compared.envName");
gvc2.Header = "environnement";
gvc2.Width = 100;
myGridView.Columns.Add(gvc2);
GridViewColumn gvc3 = new GridViewColumn();
gvc3.DisplayMemberBinding = new Binding("anomalies.Count");
gvc3.Header = "Ecarts";
gvc3.Width = 100;
myGridView.Columns.Add(gvc3);
multiCompareListOfCompared.View = myGridView;
Log.S();
}
// the class i'm trying to bind
public class ComparePair
{
public XmlFile model;
public XmlFile compared;
public List<int> anomalies;
private const int diffOnlyMarge = 10;
/// Methods ...
}
//
I am getting an output where the List is actually binded to the ListView (i can click on and use every row) but the rows are actually empty. I am getting all the three columns with their names but their rows has no "visual content" while still has the object bind to it.
What i am expecting is to see the actual values i have bind to each column.
I hope i have been clear enough. Tell me if you need more precision.
I have this form that lets user choose a (Code - Product) item from a comboxbox. input quantity and price and Add it to a list.
Loading the inventories to the form
private List<Inventory> inventories = new Inventory().read_inventory();
Setting the ComboBox with values
private void set_drop_down_inventory()
{
cb_inventory.DisplayMember = "name";
cb_inventory.DataSource = inventories;
cb_inventory.ResetText();
cb_inventory.SelectedIndex = -1;
}
When a user selects a product, it will create a new instance.
private void cb_inventory_SelectionChangeCommitted(object sender, EventArgs e)
{
var selected_inventory = (cb_inventory.SelectedItem as Inventory);
sales_order_detail = new Sales_Order_Detail(selected_inventory, 0);
tx_description.Text = selected_inventory.description;
tx_price.Text = selected_inventory.get_price_str();
}
Once the user adds the item it triggers this code.
private void btn_add_item_Click(object sender, EventArgs e)
{
// Set the inputted data into the instance before adding to the list
sales_order_detail.description = tx_description.Text.ToString();
sales_order_detail.quantity = tx_quantity.Value;
sales_order_detail.price = Convert.ToDecimal(tx_price.Text);
// Adding the instances to a List
sales_order.sales_order_details.Add(sales_order_detail);
// Sets the Datagrid to provide the data+
initialize_datagrid(sales_order_detail);
}
This is how i initialize the datagrid because i need to manually display the columns -- this is where i am not sure what to do - i believe i do not need to manually add a new row every time a user adds an item because this datagrid is bounded to the List<>, so whatever instance is added to the List<> it will be added to the grid when i trigger the dgv.Refresh()
private void initialize_datagrid(Sales_Order_Detail sales_order_detail)
{
dgv_sales_order_details.Columns.Clear();
dgv_sales_order_details.DataSource = null;
dgv_sales_order_details.Refresh();
dgv_sales_order_details.AutoGenerateColumns = false;
// Set the datasource to the list where the item is added
dgv_sales_order_details.DataSource = sales_order.sales_order_details;
DataGridViewComboBoxColumn product_code_col = new DataGridViewComboBoxColumn();
DataGridViewColumn description_col = new DataGridViewColumn();
DataGridViewColumn quantity_col = new DataGridViewColumn();
DataGridViewColumn price_col = new DataGridViewColumn();
DataGridViewColumn account_col = new DataGridViewColumn();
DataGridViewComboBoxCell product_cell = new DataGridViewComboBoxCell();
DataGridViewTextBoxCell description_cell = new DataGridViewTextBoxCell();
DataGridViewTextBoxCell amount_cell = new DataGridViewTextBoxCell();
product_cell.DisplayMember = "name";
// They have the same Datasource as the combobox above.
product_cell.DataSource = inventories;
product_code_col.CellTemplate = product_cell;
product_code_col.DataPropertyName = nameof(sales_order_detail.inventory.name); //This binds the value to your column
product_code_col.HeaderText = "Code";
product_code_col.Name = "name";
description_col.CellTemplate = description_cell;
description_col.DataPropertyName = nameof(sales_order_detail.description);
description_col.HeaderText = "Description";
description_col.Name = "description";
quantity_col.CellTemplate = amount_cell;
quantity_col.DataPropertyName = nameof(sales_order_detail.quantity);
quantity_col.HeaderText = "Quantity";
quantity_col.Name = "quantity";
quantity_col.DefaultCellStyle.Format = "0.00";
quantity_col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
price_col.CellTemplate = amount_cell;
price_col.DataPropertyName = nameof(sales_order_detail.price);
price_col.HeaderText = "Price";
price_col.Name = "price";
price_col.DefaultCellStyle.Format = "0.00";
price_col.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
dgv_sales_order_details.Columns.Add(product_code_col);
dgv_sales_order_details.Columns.Add(description_col);
dgv_sales_order_details.Columns.Add(quantity_col);
dgv_sales_order_details.Columns.Add(price_col);
dgv_sales_order_details.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}
This is the result when the item is added but as you can see the combobox column has not displayed value, it only shows the value when i click the combobox column. and when i change the value in the combobox above the list, the value in the combobox column also changes. it seems that they are binded.
My Goal is to be able add a row to the datagrid where the comboboxcolumn displays what i selected and to fix to combobox duplicated selection.
Please comment if it needs more clarification so i could correct it. Thanks!
DataGridViewComboBoxColumn c = new DataGridViewComboBoxColumn();
c.Name = "ComboColumn";
c.DataSource = dataTable;
c.ValueMember = "ID";
c.DisplayMember = "Item";
dataGridView1.Columns.Add(c);
To select a particular value you set the Value property of a given cell.
dataGridView1.Rows[rowIndexYouWant].Cells["ComboColumn"].Value = 1;
Note that the type here is important! IF you say you get a System.FormatException. This can be caused by setting the wrong type to the value.
When you set the value to 1 you are assigning an int - if for some reason you have strings in the ID column you will get the System.FormatException exception you are seeing.
If the types differ you need to either update the DataTable definition or set the value to a string:
dataGridView1.Rows[rowIndexYouWant].Cells["ComboColumn"].Value = "1";
for adding rows you might need
dataGridView1.Rows.Add();
int z=0;
for (int a = 0; a < dataGridView1.comlumncount; a++)
{
dataGridView1.Rows[z].Cells[a].Value = "yourvalue";
z++;
}
for your reference check this Link you might get your problem solved
I've managed to solve it, this is my solution. This is best solution i've come up so far. Please comment if you have any correction. so we could improve it. I hope this will help others too.
Created a DataGridView Handler so i could reuse it in the other forms and add more conditions for it be flexible.
namespace Project.Classes
{
public static class DGV_Handler
{
public static DataGridViewComboBoxColumn CreateInventoryComboBox()
{
DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
// This lets the combo box display the data selected
// I set the datasource with new instance because if i use the Datasource used in the combobox in the item selection. the combobox in the grid and that combox will be binded. if i change one combobox the other one follows.
combo.DataSource = new Inventory().read_inventory();
combo.DataPropertyName = "inventory_id";
combo.DisplayMember = "name";
combo.ValueMember = "inventory_id";
combo.Name = "inventory_id";
combo.HeaderText = "Code";
combo.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
return combo;
}
public static DataGridViewComboBoxColumn CreateGLAccountComboBox()
{
DataGridViewComboBoxColumn combo = new DataGridViewComboBoxColumn();
combo.DataSource = new Account().read();
combo.DataPropertyName = "gl_account_sales";
combo.DisplayMember = "account_name";
combo.ValueMember = "account_id";
combo.Name = "account_id";
combo.HeaderText = "Account";
combo.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
return combo;
}
public static DataGridViewTextBoxColumn CreateTextBox(string dataproperty, string headertext, string name, bool is_numbers)
{
DataGridViewTextBoxColumn textbox = new DataGridViewTextBoxColumn();
textbox.DataPropertyName = dataproperty;
textbox.HeaderText = headertext;
textbox.Name = name;
if (is_numbers)
{
textbox.DefaultCellStyle.Format = "0.00";
textbox.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
}
return textbox;
}
}
}
When the form is loaded i initialize the datagrid like this.
private void initialize_datagrid()
{
dgv_sales_order_details.Columns.Clear();
dgv_sales_order_details.Refresh();
dgv_sales_order_details.AutoGenerateColumns = false;
dgv_sales_order_details.DataSource = bindingSource1;
dgv_sales_order_details.Columns.Add(DGV_Handler.CreateInventoryComboBox());
dgv_sales_order_details.Columns.Add(DGV_Handler.CreateTextBox("description","Description", "description", false));
dgv_sales_order_details.Columns.Add(DGV_Handler.CreateTextBox("quantity","Quantity","quantity", true));
dgv_sales_order_details.Columns.Add(DGV_Handler.CreateTextBox("price", "Price", "price", true));
dgv_sales_order_details.Columns.Add(DGV_Handler.CreateGLAccountComboBox());
dgv_sales_order_details.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dgv_sales_order_details.RowHeadersVisible = false;
dgv_sales_order_details.EditMode = DataGridViewEditMode.EditOnEnter;
}
Code when adding a new row
private void btn_add_item_Click(object sender, EventArgs e)
{
if(validate_selection())
{
// Set the properties to be included in the DGV Column
var selected_row = (cb_inventory.SelectedValue as Inventory);
var selected_gl_account = (cb_gl_account.SelectedValue as Account);
string description = tx_description.Text;
decimal quantity = tx_quantity.Value;
decimal price = Convert.ToDecimal(tx_price.Text);
int gl_account_id = selected_gl_account.account_id;
// When something new is added to the bindingsource, the DGV will be refresh
bindingSource1.Add(new Sales_Order_Detail(selected_row, description, quantity, price, 0, gl_account_id));
clear_item_selection();
}
}
Result
I create my DataGridTemplateColumn with a ComboBox inside in my Code. When I change the Height of my DataGridRow I want the ComboBox to always fill the Cell. But as it is now my ComboBox always stays the same Height. It works with the Width though. Here is what I have tried so far:
(For Information the whole code)
ItemsPanelTemplate IPT = null;
DataGridTemplateColumn DGTC = new DataGridTemplateColumn();
DataTemplate DataTMP = null;
Binding bind = new Binding(strPropertyname);
FrameworkElementFactory cboFactory = new FrameworkElementFactory(typeof(ComboBox));
cboFactory.SetValue(ComboBox.HorizontalAlignmentProperty, HorizontalAlignment.Stretch);
cboFactory.SetValue(ComboBox.VerticalAlignmentProperty, VerticalAlignment.Stretch);
cboFactory.SetValue(ComboBox.ItemsSourceProperty, DTCBOSource.DefaultView);
cboFactory.SetValue(ComboBox.IsEditableProperty, false);
cboFactory.SetValue(ComboBox.IsTextSearchEnabledProperty, true);
cboFactory.SetValue(ComboBox.IsEnabledProperty, !blnIsReadOnly);
cboFactory.SetValue(ComboBox.SelectedValuePathProperty, DTCBOSource.Columns[0].ColumnName);
cboFactory.SetValue(ComboBox.DisplayMemberPathProperty, DTCBOSource.Columns[1].ColumnName);
Binding bHeight = new Binding();
bHeight.Source = _DGSource;
bHeight.Path = new PropertyPath("RowHeight");
bHeight.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
cboFactory.SetValue(ComboBox.HeightProperty, bHeight);
cboFactory.AddHandler(ComboBox.GotFocusEvent, new RoutedEventHandler(DG_EditingElementEnter));
cboFactory.AddHandler(ComboBox.LostFocusEvent, new RoutedEventHandler(DG_EditingElementLeave));
IPT = (ItemsPanelTemplate)(Application.Current.TryFindResource("CBOVirtualPanel"));
if (IPT != null)
{
cboFactory.SetValue(ComboBox.ItemsPanelProperty, IPT);
}
bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
bind.NotifyOnTargetUpdated = true;
//bind.Mode = BindingMode.TwoWay;
cboFactory.SetBinding(ComboBox.SelectedValueProperty, bind);
DataTMP = new DataTemplate();
DataTMP.VisualTree = cboFactory;
DGTC.CellTemplate = DataTMP;
DGTC.SortMemberPath = strPropertyname;
//_DGSource.TargetUpdated += DG_CellValueChanged_Event;
return DGTC;
I've a DataGrid defined as follow:
private void CreateSemanticChannels()
{
myGrid.Style = (Style)FindResource("MyDataGrid");
var col1 = new DataGridTextColumn
{
Header = "FUNCTIONALITY",
Binding = new Binding("Functionality"),
};
myGrid.Columns.Add(col1);
var col2 = new DataGridTextColumn
{
Header = "ASSOCIATED TO",
Binding = new Binding("AssociatedTo"),
FontWeight = FontWeights.SemiBold
};
myGrid.Columns.Add(col2);
DataTemplate buttonTemplate = new DataTemplate();
FrameworkElementFactory buttonFactory = new FrameworkElementFactory(typeof(Button));
buttonTemplate.VisualTree = buttonFactory;
var col3 = new DataGridTemplateColumn
{
Header = "STATUS",
CellTemplate = buttonTemplate
};
myGrid.Columns.Add(col3);
// AGGIORNAMENTO CONTENUTO E VISUALIZZAZIONE
UpdateGrid();
myGrid.SelectedIndex = -1;
advSettingGrid.Children.Add(myGrid);
}
Where in UpdateGrid I add the item to the DataGrid.
myGrid.Items.Add(newRecord);
I want to modify the Style of each Button so I have started following this post but I have always ItemSource empty.
I read this, and actually I forgot to set the ItemSource property. So I defined the List of my object as _recordList and in the XAML I added this property
<Setter Property="BindingGroup" Value="{Binding Path=_recordList}"></Setter>
However, I still have ItemSource empty.
Any help is really appreciate!
i am using a datagridview in that i am using a datagridviewcomboboxcolumn, comboboxcolumn is displaying text but the problem is i want to select the first item of comboboxcolumn by default how can i do this
DataGridViewComboBoxColumn dgvcb = (DataGridViewComboBoxColumn)grvPackingList.Columns["PackingUnits"];
Globals.G_ProductUtility G_Utility = new Globals.G_ProductUtility();
G_Utility.addUnittoComboDGV(dgvcb);
DataSet _ds = iRawMaterialsRequest.SelectBMR(bmr_ID, branch_ID, "PACKING");
grvPackingList.DataSource = _ds.Tables[0];
int i = 0;
foreach (DataRow dgvr in _ds.Tables[0].Rows)
{
grvPackingList.Rows[i].Cells["Units"].Value = dgvr["Units"].ToString();
i++;
}
The values available in the combobox can be accessed via items property
row.Cells[col.Name].Value = (row.Cells[col.Name] as DataGridViewComboBoxCell).Items[0];
the best way to set the value of a datagridViewComboBoxCell is:
DataTable dt = new DataTable();
dt.Columns.Add("Item");
dt.Columns.Add("Value");
dt.Rows.Add("Item1", "0");
dt.Rows.Add("Item1", "1");
dt.Rows.Add("Item1", "2");
dt.Rows.Add("Item1", "3");
DataGridViewComboBoxColumn cmb = new DataGridViewComboBoxColumn();
cmb.DefaultCellStyle.Font = new Font("Tahoma", 8, FontStyle.Bold);
cmb.DefaultCellStyle.ForeColor = Color.BlueViolet;
cmb.FlatStyle = FlatStyle.Flat;
cmb.Name = "ComboColumnSample";
cmb.HeaderText = "ComboColumnSample";
cmb.DisplayMember = "Item";
cmb.ValueMember = "Value";
DatagridView dvg=new DataGridView();
dvg.Columns.Add(cmb);
cmb.DataSource = dt;
for (int i = 0; i < dvg.Rows.Count; i++)
{
dvg.Rows[i].Cells["ComboColumnSample"].Value = (cmb.Items[0] as
DataRowView).Row[1].ToString();
}
It worked with me very well
If I had known about doing it in this event, it would have saved me days of digging and
trial and errors trying to get it to set to the correct index inside the CellEnter event.
Setting the index of the DataGridViewComboBox is the solution I have been looking for.....THANKS!!!
In reviewing all the issues other coders have been experiencing with trying to set
the index inside of a DataGridViewComboBoxCell and also after looking over your code,
all that anyone really needs is:
1. Establish the event method to be used for the "EditingControlShowing" event.
2. Define the method whereby it will:
a. Cast the event control to a ComboBox.
b. set the "SelectedIndex" to the value you want.
In this example I simply set it to "0", but you'd probably want to apply so real life logic here.
Here's the code I used:
private void InitEvents()
{
dgv4.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler( dgv4EditingControlShowing );
}
private void dgv4EditingControlShowing( object sender, DataGridViewEditingControlShowingEventArgs e )
{
ComboBox ocmb = e.Control as ComboBox;
if ( ocmb != null )
{
ocmb.SelectedIndex = 0;
}
}
If DataGridViewComboBoxCell already exist:
DataTable dt = new DataTable();
dt.Columns.Add("Item");
dt.Columns.Add("Value");
dt.Rows.Add("Item 1", "0");
dt.Rows.Add("Item 2", "1");
dt.Rows.Add("Item 3", "2");
dt.Rows.Add("Item 4", "3");
for (int i = 0; i < dvg.Rows.Count; i++)
{
DataGridViewComboBoxCell comboCell = (DataGridViewComboBoxCell)dvg.Rows[i].Cells[1];
comboCell.DisplayMember = "Item";
comboCell.ValueMember = "Value";
comboCell.DataSource = dt;
};
I've had some real trouble with ComboBoxes in DataGridViews and did not find an elegant way to select the first value. However, here is what I ended up with:
public static void InitDGVComboBoxColumn<T>(DataGridViewComboBoxCell cbx, List<T> dataSource, String displayMember, String valueMember)
{
cbx.DisplayMember = displayMember;
cbx.ValueMember = valueMember;
cbx.DataSource = dataSource;
if (cbx.Value == null)
{
if(dataSource.Count > 0)
{
T m = (T)cbx.Items[0];
FieldInfo fi = m.GetType().GetField(valueMember, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
cbx.Value = fi.GetValue(m);
}
}
}
It basically sets the .Display and .ValueMember properties of the DataGridViewComboBoxCell and uses a List as DataSource. It then takes the first item, and uses reflection to get the value of the member that was used as ValueMember and sets the selected value via .Value
Use it like this:
public class Customer
{
private String name;
public String Name
{
get {return this.name; }
set {this.name = value; }
}
private int id;
public int Id
{
get {return this.id; }
set {this.id = value; }
}
}
public class CustomerCbx
{
private String display;
public String Display
{
get {return this.display; }
set {this.display = value; }
}
private Customer value;
public Customer Value
{
get {return this.value; }
set {this.value = value; }
}
}
public class Form{
private void Form_OnLoad(object sender, EventArgs e)
{
//init first row in the dgv
if (this.dgv.RowCount > 0)
{
DataGridViewRow row = this.dgv.Rows[0];
DataGridViewComboBoxCell cbx = (DataGridViewComboBoxCell)row.Cells[0];
Customer c1 = new Customer(){ Name = "Max Muster", ID=1 };
Customer c2 = new Customer(){ Name = "Peter Parker", ID=2 };
List<CustomerCbx> custList = new List<CustomerCbx>()
{
new CustomerCbx{ Display = c1.Name, Value = c1},
new CustomerCbx{ Display = c2.Name, Value = c2},
}
InitDGVComboBoxColumn<CustomerCbx>(cbx, custList, "display", "value");
}
}
}
}
It seems pretty hacky to me, but I couldn't find any better way so far (that also works with complex objects other than just Strings). Hope that will save the search for some others ;)
You need to set the Items for the new cell. This must be auto done by the column when creating a new row from the UI.
var cell = new DataGridViewComboBoxCell() { Value = "SomeText" };
cell.Items.AddRange(new String[]{"SomeText", "Abcd", "123"});
something different worked for me what i did is to simply set the value of dtataGridComboBox when ever new record is added bu user with 'userAddedRow' event. For the first row I used the code in constructor.
public partial class pt_drug : PatientDatabase1_3._5.basic_templet
{
public pt_drug()
{
InitializeComponent();
dataGridView_drugsDM.Rows[0].Cells[0].Value = "Tablet";
}
private void dataGridView_drugsDM_UserAddedRow(object sender, DataGridViewRowEventArgs e)
{
dataGridView_drugsDM.Rows[dataGridView_drugsDM.RowCount - 1].Cells[0].Value = "Tablet";
}
}
Here the solution I have found : select the cell you are interested in so you can cast it to a combobox.
this.Invoke((MethodInvoker)delegate
{
this.dataGridView1.CurrentCell = dataGridView1.Rows[yourRowindex].Cells[yourColumnIndex];
this.dataGridView1.BeginEdit(true);
ComboBox comboBox = (ComboBox)this.dataGridView1.EditingControl;
comboBox.SelectedIndex += 1;
});