How to add new items to combobox which is bound to Entities? - c#

Design class which is generated by C# :
//
// usepurposeComboBox
//
this.usepurposeComboBox.DataSource = this.usepurposeBindingSource;
this.usepurposeComboBox.DisplayMember = "Name";
this.usepurposeComboBox.FormattingEnabled = true;
this.usepurposeComboBox.Location = new System.Drawing.Point(277, 53);
this.usepurposeComboBox.Name = "usepurposeComboBox";
this.usepurposeComboBox.Size = new System.Drawing.Size(218, 21);
this.usepurposeComboBox.TabIndex = 4;
this.usepurposeComboBox.ValueMember = "id";
//
// usepurposeBindingSource
//
this.usepurposeBindingSource.DataSource = typeof(mydatabaseEntities.usepurpose);
Then I bound the BindingSource (usepurposeBindingSource) to Entities :
usepurposeBindingSource.DataSource = mydatabaseEntities.usepurposes;
And I can not add a new row to usepurposeComboBox because it's been bound. Is there a workaround ?

The shortest way is to add a new row to your dataTable and then bind your comboBox to it something like this:
Company comps = new Company();
//pupulate dataTable with data
DataTable DT = comps.getCompaniesList();
//create a new row
DataRow DR = DT.NewRow();
DR["c_ID"] = 0;
DR["name"] = "Add new Company";
DR["country"] = "IR";
//add new row to data table
DT.Rows.Add(DR);
//Binding DataTable to cxbxCompany
cxbxCompany.DataSource = DT;
cxbxCompany.DisplayMember = "name";
cxbxCompany.ValueMember = "c_ID";

I'm assuming that you want to add for example a first item sometimes called "Choose One" as if you want to live data you should just see where the data comes from and add more items to that "table".
this.usepurposeBindingSource is an object ... why not adding into it before it binds?
if it's a List<T> this will be fine
this.usepurposeBindingSource.Insert(0, new T() {
Name = "Choose one",
Id = ""
});
Then Bind() it...
Remember to validate as it's a string and will not be the object you want
This is working:
List<MyObject> usepurposeBindingSource { get; set; }
private void FillUpData()
{
// Simulating an External Data
if (usepurposeBindingSource == null || usepurposeBindingSource.Count == 0)
{
this.usepurposeBindingSource = new List<MyObject>();
this.usepurposeBindingSource.Add(new MyObject() { Name = "A", ID = 1 });
this.usepurposeBindingSource.Add(new MyObject() { Name = "B", ID = 2 });
this.usepurposeBindingSource.Add(new MyObject() { Name = "C", ID = 3 });
}
}
private void FillUpCombo()
{
FillUpData();
// what you have from design
// comment out the first line
//this.usepurposeComboBox.DataSource = this.usepurposeBindingSource;
this.usepurposeComboBox.DisplayMember = "Name";
this.usepurposeComboBox.FormattingEnabled = true;
this.usepurposeComboBox.Location = new System.Drawing.Point(277, 53);
this.usepurposeComboBox.Name = "usepurposeComboBox";
this.usepurposeComboBox.Size = new System.Drawing.Size(218, 21);
this.usepurposeComboBox.TabIndex = 4;
this.usepurposeComboBox.ValueMember = "id";
// to do in code:
this.usepurposeBindingSource.Insert(0, new MyObject() { Name = "Choose One", ID = 0 });
// bind the data source
this.usepurposeComboBox.DataSource = this.usepurposeBindingSource;
}
The trick is to comment out the DataSource line and do it in your code, inserting one more element into your object that is from your Model
//this.usepurposeComboBox.DataSource = this.usepurposeBindingSource;

The simplest way to do this, is to wrap your BindingSource with some kind of "ViewModel". The new class will return a "complete" list of items - both those provided from the original binding source, as well as those "additional" items.
You can then bind the new wrapper to your combobox.
I wrote an article about this a while back... It's not my finest work, and it's probably a bit outdated, but it should get you there.

I resolved it on my own. I created a new unbound combobox then bind it to a datatable. Not sure if it's the best way but it works for me. Thanks for all of your suggestions. :)
private void FillCombobox()
{
using (mydatabaseEntities mydatabaseEntities = new mydatabaseEntities())
{
List<usepurpose> usepurposes = mydatabaseEntities.usepurposes.ToList();
DataTable dt = new DataTable();
dt.Columns.Add("id");
dt.Columns.Add("Name");
dt.Rows.Add(-1, "test row");
foreach (usepurpose usepurpose in usepurposes)
{
dt.Rows.Add(usepurpose.id, usepurpose.Name);
}
usepurposeComboBox.ValueMember = dt.Columns[0].ColumnName;
usepurposeComboBox.DisplayMember = dt.Columns[1].ColumnName;
usepurposeComboBox.DataSource = dt;
}
}

Check out this link: http://forums.asp.net/t/1695728.aspx/1?
In asp you can add this to insert an empty line:
<asp:DropDownList ID="CustomerDropDownList" runat="server"
DataSourceID="CustomerEntityDataSource" DataTextField="CustomerId"
DataValueField="CustomerId" AppendDataBoundItems="true">
<asp:ListItem Text="Select All Customers" Value="" />
</asp:DropDownList>
Or in code behind:
DropDownList1.AppendDataBoundItems = true;
DropDownList1.Items.Add(new ListItem("Select All Customers", "-1"));

Related

Bind a CheckedlistBox to DataSource c#

I want to set my data from my database into the CheckedListBox but with my code I only get error messages that say DataBinding only accepts List or ListSource.
Also with debugging mode I don't even get an error message the CheckedListBox just stays empty.
DataClasses1DataContext d = new DataClasses1DataContext();
////
var query = from pers in d.Person select pers;
BindingList<Person> personen = new BindingList<Person> { new Person { Name = "Name"} };
clVorfahr.DataSource = personen;
clVorfahr.DisplayMember = "Name";
clVorfahr.ValueMember = "Name";
clVorfahr.Refresh();
You are setting the wrong data source. It should be personen not Name.
clVorfahr.DataSource = personen;
clVorfahr.DisplayMember = "Name";

How to Use Virtual Mode for large data in DataGridView

I am posting to see if there is a way to improve some legacy code. The code will populate a DataGridView with x amount of rows. Initially, the code worked fine as the populating data was of a small quantity. However, there has been an extreme increase in data and I am finding that the performance in populating the DataGridView to be very slow.
Basically, I know there are several considerations (Virtual Mode, for instance). However, the approach that I want to take is using an array or List (and then convert it to an array) and add the range of the row by calling Rows.AddRange(array). However, I am having trouble implementing it.
As it stands, this is what code exists:
if (value !=0)
{
int row = 0;
dataGridView1.AddRow();
dataGridView1.Rows[row].Cells[0] = "Test";
dataGridView1.Rows[row].Cells[1] = 9;
dataGridView1.Rows[row].Cells[2] = "Test Two";
dataGridView1.Rows[row].Cells[3] = "Test Three";
row++;
}
if (valueTwo !=0)
{
dataGridView1.AddRow();
dataGridView1.Rows[row].Cells[0] = "Test";
dataGridView1.Rows[row].Cells[1] = 9;
dataGridView1.Rows[row].Cells[2] = "Test Two";
dataGridView1.Rows[row].Cells[3] = "Test Three";
row++;
}
So, this is not efficient at all, of course. I know .AddRow() is a taxing method in itself and individually adding rows, one-by-one is not great.
I have tried something like:
object[] data = {"Test", 9, "Test Two", "Test Three"};
List<DataGridViewRow> list = new List<DataGridViewRow>();
for (int i = 0; i < data.Length; i++)
{
DataGridViewRow row = new DataGridViewRow();
row.SetValues(data[i]);
list.Add(row);
}
dataGridViewRow1.Rows.AddRange(list.ToArray());
However, doing this gets me a NullPointerException on the SetValues line.
I understand that the best way of doing this is either make a DataTable or use Virtual Mode but I want to try out using this method of adding the range and passing in a container for the data, rather than adding a row.
I hope I am clear with my explanation. Let me know if I need to further explain.
EDIT: I think using Virtual Mode is the best way to go. I am not sure how to really do it, though. I checked MSN's tutorial but I was slightly confused by it. If I were to implement Virtual Mode for 100,000 rows, how would I go about doing it. Nothing really fancy, just displaying a total of 10,000 rows.
i can prefer DataTable is the correct approach,
but still if you want to add data to your gridView dynamically,
first you need to add columns then rows.
private void Form5_Load(object sender, EventArgs e)
{
var lstTemp = new List<test>();
for (int i = 0; i < 10; i++)
lstTemp.Add(new test() { Name = "Test", No = i, Desc = "Desc " + i, Desc1 = "Desc1 " + i });
dataGridView1.Columns.Add("Name", "Name");
dataGridView1.Columns.Add("No", "Number");
dataGridView1.Columns.Add("Desc", "Description1");
dataGridView1.Columns.Add("Desc1", "Description2");
foreach (var temp in lstTemp)
{
DataGridViewRow row = (DataGridViewRow) dataGridView1.Rows[0].Clone();
row.Cells[0].Value = temp.Name;
row.Cells[1].Value = temp.No;
row.Cells[2].Value = temp.Desc;
row.Cells[3].Value = temp.Desc1;
dataGridView1.Rows.Add(row);
}
}
public class test
{
public string Name { get; set; }
public int No { get; set; }
public string Desc { get; set; }
public string Desc1 { get; set; }
}
this might help you,
for your case you need to add columns before rows,
object[] data = { "Test", 9, "Test Two", "Test Three" };
dataGridView1.Columns.Add("Name", "Name");
dataGridView1.Columns.Add("No", "Number");
dataGridView1.Columns.Add("Desc", "Description1");
dataGridView1.Columns.Add("Desc1", "Description2");
for (int i = 0; i < 10; i++)
dataGridView1.Rows.Add(data);
Try to use a BindingList that you populate with your data, you can have a class to map the propreties or use a dynamic one. You have to frist create the cols so you can Bind de data: hereĀ“s one example:
DataGridViewCell cell = new DataGridViewTextBoxCell();
DataGridViewTextBoxColumn colFileName = new DataGridViewTextBoxColumn()
{
CellTemplate = cell,
Name = "Value1",
HeaderText = "Value 1",
DataPropertyName = "Col1"
};
DataGridViewCell cell2 = new DataGridViewTextBoxCell();
DataGridViewTextBoxColumn colFileName2 = new DataGridViewTextBoxColumn()
{
CellTemplate = cell2,
Name = "Value2",
HeaderText = "Value 2",
DataPropertyName = "Col2"
};
dataGridView1.Columns.Add(colFileName);
dataGridView1.Columns.Add(colFileName2);
List<DataPopulate> list = new List<DataPopulate>();
list.Add(new DataPopulate() { Col1 = "tes1", Col2 = "teste2"});
list.Add(new DataPopulate() { Col1 = "tes1", Col2 = "teste2" });
list.Add(new DataPopulate() { Col1 = "tes1", Col2 = "teste2" });
var dataPopulateList = new BindingList<DataPopulate>(list);
dataGridView1.DataSource = dataPopulateList;

How do I format hyperlink column gridview in my codebehind file?

I am trying to make a column a hyperlink in my grid view. I am Using Umbraco 6 childpages as datasource. I have a link but at the moment it's going to /website/masterpages/url with %20% in the spaces
My View is like this:
<asp:hyperlinkfield datatextfield="title" datanavigateurlfields="title" headertext="Title" />
and code behind like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
HyperLinkField title = new HyperLinkField();
string[] dataNavigateUrlFields = { "title" };
title.DataTextField = "title";
title.DataNavigateUrlFields = dataNavigateUrlFields;
title.HeaderText = "Title";
title.DataNavigateUrlFormatString = "item.Url";
// Create a BoundField object to display the company's city.
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[3] { new DataColumn("title", typeof(String)),
new DataColumn("lastUpdated", typeof(string)),
new DataColumn("theme",typeof(string)) });
int i = 0;
foreach (var item in uQuery.GetCurrentNode().ChildrenAsList)
{
var dateTimeString = item.GetProperty("lastUpdated").Value.ToString();
var dateTime = System.Xml.XmlConvert.ToDateTime(dateTimeString);
dt.Rows.Add(item.Name, dateTime.ToString("dd.MM.yyyy"), item.GetProperty("theme").Value.ToString());
}
Session["data"] = dt;
Cache["Data"] = dt;
Practice.DataSource = dt;
Practice.DataBind();
}
can anyone tell me what I'm doing wrong - thanks
I figured it out, but adding an extra column to the table called name (as this is not displayed unless you reference it on the output, removing:
HyperLinkField title = new HyperLinkField();
string[] dataNavigateUrlFields = { "title" };
title.DataTextField = "title";
title.DataNavigateUrlFields = dataNavigateUrlFields;
title.HeaderText = "Title";
title.DataNavigateUrlFormatString = "item.Url";
// Create a BoundField object to display the company's city.
and changing the datatextfield to "name" ie DataTextField="name".
If anyone else gets stuck:)

Attribute to chance cell to combobox

I use dataGridView.DataSource = myList; to populate a dataGridView.
I use the following code to hide a class member:
[System.ComponentModel.Browsable(false)]
public string SomeInformation { get; set; }
But, is there also a way to say that a class member should be represented as a ComboBox?
If not, is there any way that I can change it with code? I tried the following:
DataGridViewComboBoxCell comboBoxCell = new DataGridViewComboBoxCell();
comboBoxCell.DataSource = State.Instance.ProductCategories.ToList();
dataGridView[2, 0] = comboBoxCell;
dataGridView[2, 0].Value = State.Instance.ProductCategories.ToList()[0];
The value of the field will be fine, but there is still no ComboBox.
Any help?
Edit:
I now use the following code:
dataGridView.DataSource = State.Instance.Products;
dataGridView.DataError += delegate(object o, DataGridViewDataErrorEventArgs args)
{
MessageBox.Show(args.Exception.Message);
};
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.DataPropertyName = "Categorie";
col.Name = "Categorie";
col.Visible = true;
col.HeaderText = "Categorie";
col.DataSource = State.Instance.ProductCategories.ToList();
col.DisplayMember = "Name";
col.DisplayIndex = 1;
dataGridView.Columns.Add(col);
dataGridView.CellEndEdit += delegate(object o, DataGridViewCellEventArgs args)
{
State.Instance.Save();
// If I check the value here, it is a string.
};
But when I save the state, the value is not being changed. Can that be because I added the column myself and it does not know where to save it?
[System.ComponentModel.Browsable(false)]
public ProductCategory Categorie { get; set; }
And in the CellEndEdit event, I only get the string back, but not the whole object.
You can set DataGridView.AutoGenerateColumns=false and then add all columns in code, or auto generate columns and then add your custom column (change DisplayIndex to set its position):
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.DataPropertyName = "SomeInformation";
col.Name = "colSomeInformation";
col.Visible = true;
col.HeaderText = "Some Information"
col.DataSource = State.Instance.ProductCategories.ToList();
// set other column properties here...
dataGridView.Columns.Add(col);
I once had to autogenerate datagridview's columns of different types based on external settings, and I used xml config files for this. As far as I know, there's no built-in solution to do it.
EDIT:
How the ValueMember works:
class ProductCategory
{
public int ID {get;set;}
public string Name {get;set;}
}
class Product
{
public int ID {get;set;}
public string Name {get;set;}
public int CategoryID {get;set;}
}
// Example data binding:
BindingList<Products> bl = new BindingList<Products>(State.Instance.Products.ToList());
BindingSource bs = new BindingSource();
bs.DataSource=bl;
dataGridView.DataSource = bs;
DataGridViewComboBoxColumn col = new DataGridViewComboBoxColumn();
col.DataSource = State.Instance.Categories.ToList();
col.DataPropertyName = "CategoryID";
col.DisplayMember= "Name"; // name of category
col.ValueMember ="ID"; // id of category
I am pretty sure that that is not possible.

How to set a DataGridView column to a DataGridViewComboBoxColumn?

Here is my code:
DataSet data = new DataSet();
data.ReadXml("data.xml");
DataGridView grid = new DataGridView();
var genreCboBoxItems = data.Tables[0].AsEnumerable().Select(genre => genre.Field<string>("genre")).Distinct().ToArray();
// TODO: Make is so the 'genre' column in grid is a combo box?
grid.DataSource = data.Tables[0];
grid.Dock = DockStyle.Fill;
this.Controls.Add(grid);
*edit: genreCboBoxItems
Try this: (not tested)
var column = new DataGridViewComboBoxColumn();
column.DataSource = data.Tables[0].AsEnumerable().
Select(genre => new { genre = genre.Field<string>("genre") }).Distinct();
column.DataPropertyName = "genre";
column.DisplayMember = "genre";
column.ValueMember = "genre";
grid.DataSource = data.Tables[0];
// Instead of the below line, You could use grid.Columns["genre"].Visible = false;
grid.Columns.Remove("genre");
grid.Columns.Add(column);
This might help you cast DataGridViewColumn to DataGridViewComboBox.
First create DataGridViewComboBoxColumn using designer with proper name. Then say you have a list of String list and other string values to bind to that datagridview then use this code:
Below code will bind a list to two DataGridViewTextBoxCell and a DataGridViewComboBoxCell. Note AllCriterias is a list with two string values and a list of string. DGVEligibilityCriteria is the grid name.
for (int i = 0; i < AllCriterias.Count; i++)
{
DataGridViewTextBoxCell Cmb1 = (DataGridViewTextBoxCell)DGVEligibilityCriteria.Rows[i].Cells[0];
Cmb1.Value = AllCriterias[i].Name;
DataGridViewTextBoxCell Cmb2 = (DataGridViewTextBoxCell)DGVEligibilityCriteria.Rows[i].Cells[1];
Cmb2.Value = AllCriterias[i].Type;
DataGridViewComboBoxCell Cmb = (DataGridViewComboBoxCell)DGVEligibilityCriteria.Rows[i].Cells[2];
foreach (var filtervalue in AllCriterias[i].FilterValues)
{
Cmb.Items.Add(filtervalue);
}
}
Need to display the fist index as default by setting selectindex property.
Use this code : Here "filterValues" is the name of the DataGridViewComboBoxCell which u created in the datagridview designer.
foreach (DataGridViewRow row in DGVEligibilityCriteria.Rows)
{
row.Cells["filterValues"].Value = (row.Cells["filterValues"] as DataGridViewComboBoxCell).Items[0];
}

Categories

Resources