I'm trying to fill a dropdownlist from a Hashtable, the HashTable keys & values pulled from database, private Hashtable myHashTable = new Hashtable();
using the following method:
void LoadmyHashTable()
{
bussinessObject bs = new bussinessObject();
myDataset ds = new myDataset();
ds = bs.GetPosType(-1);
int rowsCount = ds.myTable.Rows.Count;
for (int i = 0; i < rowsCount; i++)
{
myHashTable.Add(ds.myTable.Rows[i]["dTypeName"],ds.myTable.Rows[i]["dTypeId"] );
}
}
then, after call the method in page load() and trying to fill the dropdownlist with the hashTable values:
myDropdownlist.DataSource = myHashTable;
myDropdownlist.DataTextField = "key";
myDropdownlist.DataValueField = "value";
myDropdownlist.DataBind();
The problem my dropdownlist appear with empty!
Thanks in advance.
ASP.NET,C#
I have modify code as below please try it.
void LoadmyHashTable()
{
bussinessObject bs = new bussinessObject();
DataSet ds = new DataSet();
ds = bs.GetPosType(-1);
if (ds.Tables.Count > 0 )
{
for (int i = 0; i < ds.Tables[0].Rows.Count-1; i++)
{
myHashTable.Add(ds.Tables[0].Rows[i]["dTypeId"], ds.Tables[0].Rows[i]["dTypeName"]);
}
}
}
use code for page load as below
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
LoadmyHashTable();
if (myHashTable.Count > 0)
{
myDropdownlist.DataSource = myHashTable;
myDropdownlist.DataTextField = "Value";
myDropdownlist.DataValueField = "Key";
myDropdownlist.DataBind();
}
}
}
Hope this will helps you...happy coding...
The DataTextField and DataValueField values need to each correspond to a property in the binding source. Your code assumes a collection of objects that have at minimum a property named "key" and another named "value". Since this is not true, no items get bound.
EDIT: This code hasn't been tested at all, but you should be able to use LINQ to project your dataset into an anonymous collection:
var myHashTable = ds.myTable.Rows.Select( row => new { key = row["dTypeName"], value = row["dTypeId"] } );
Then the binding you are using should work.
Related
I need to create a combobox autocomplete which display text Name but when I click on text it gets value "ID" binding with "Name". I have already created a code but it is not working and I'm so confusing with set display text and value into combobox and autocomplete data-source binding.
private void loadAutoCompleteValues()
{
autoCompleteCombo.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
autoCompleteCombo.AutoCompleteSource = AutoCompleteSource.CustomSource;
DataTable products;
con.MysqlQuery("select * from products");
products = con.QueryEx();
Dictionary<string, string> comboSource = new Dictionary<string, string>();
for (int i = 0; i < products.Rows.Count; i++)
{
DataRow dr = products.Rows[i];
comboSource.Add(dr["id"].ToString(), dr["name"].ToString());
}
autoCompleteCombo.DataSource = new BindingSource(comboSource, null);
autoCompleteCombo.DisplayMember = "Value";
autoCompleteCombo.ValueMember = "Key";
}
private void autoCompleteCombo_SelectedIndexChanged(object sender, EventArgs e)
{
string key = ((KeyValuePair<string, string>)autoCompleteCombo.SelectedItem).Key;
string value = ((KeyValuePair<string, string>)autoCompleteCombo.SelectedItem).Value;
MessageBox.Show(key + " " + value);
}
I may be incorrect here, however using your code I simply added the line autoCompleateCombo.AutoCompleteSource = AutoCompleteSource.ListItems; to your code and it worked as expected.
autoCompleateCombo.DataSource = new BindingSource(comboSource, null);
autoCompleateCombo.DisplayMember = "Value";
autoCompleateCombo.ValueMember = "Key";
autoCompleateCombo.AutoCompleteSource = AutoCompleteSource.ListItems; //<-- Added this line
I have a problem with setting a correct data property for DataPropertyName of DataGridViewComboBoxColumn. I have a BindingSource and I set its DataSource to BindingList of custom objects. These objects have properties which I'd like to assign as columns in DataGridView (pluginsDataGrid):
var source = new BindingSource {DataSource = _plugins};
pluginsDataGrid.AutoGenerateColumns = false;
pluginsDataGrid.DataSource = source;
Everything's fine when I have a simple string as a property - it is Name:
using (var nameCol = new DataGridViewTextBoxColumn())
{
nameCol.DataPropertyName = "Name";
nameCol.Name = "Name";
pluginsDataGrid.Columns.Add(nameCol);
}
but I don't know how to set DataGridViewComboBoxColumn options. I gave it a try this way:
using (var depCol = new DataGridViewComboBoxColumn())
{
depCol.DataPropertyName = "Dependencies";
depCol.Name = "Dependencies";
pluginsDataGrid.Columns.Add(depCol);
}
where Dependencies is a list of strings. But it is not working. What kind of property should be assign to it?
You need to specify DataSource for the column, example:
comboboxColumn.DataSource = collection;
comboboxColumn.ValueMember = ColumnName;
comboboxColumn.DisplayMember = ValueMember;
In your case use DataBindingComplete event to psecify collection:
void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
DataGridViewComboBoxCell comboCell = (DataGridViewComboBoxCell)dataGridView1.Rows[i].Cells["Dependencies"];
[Plugin_Type] entry = dataGridView1.Rows[i].DataBoundItem as [Plugin_Type];
comboCell.DataSource = entry.[YOUR_PROPERTY];
}
}
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"));
I'm using BindingSource.Find() to return to the user's position after refreshing a DataGridView. I use BindingSource.Find() and a RowID as the DataColumn I'm searching on. Unfortunately, Oracle can return two RowIDs that differ only in their case.
BindingSource.Find() returns the first match regardless of case.
Looking at the MSDN docs:
public int Find(string propertyName, Object key)
it says that the propertyName comparison is case-insensitive, but does not mention whether the key comparison is.
Does anyone know how to make BindingSource.Find case sensitive?
For a DataView all you should need to do is set the CaseSensitive property of the parent DataTable to true. I just quickly prototyped that with the following code and it works fine:
public Form1()
{
InitializeComponent();
DataSet set1 = new DataSet();
// Some xml data to populate the DataSet with.
string testXml =
"<?xml version='1.0' encoding='UTF-8'?>" +
"<numbers>" +
"<number><name>one</name></number>" +
"<number><name>two</name></number>" +
"<number><name>Two</name></number>" +
"<number><name>three</name></number>" +
"</numbers>";
// Read the xml.
StringReader reader = new StringReader(testXml);
set1.ReadXml(reader);
// Get a DataView of the table contained in the dataset.
DataTableCollection tables = set1.Tables;
// Set the CaseSensetive property
tables[0].CaseSensitive = true;
DataView view1 = new DataView(tables[0]);
// Create a DataGridView control and add it to the form.
dataGridView1.AutoGenerateColumns = true;
// Create a BindingSource and set its DataSource property to
// the DataView.
BindingSource source1 = new BindingSource();
source1.DataSource = view1;
// Set the data source for the DataGridView.
dataGridView1.DataSource = source1;
// Set the Position property to the results of the Find method.
int itemFound = source1.Find("name", "Two");
source1.Position = itemFound;
}
For other types of IBindingList you need, as the docs say, an underlying list that implements a Find which is case sensitive. For completeness I have shown the code to do this below:
public Form1()
{
InitializeComponent();
// This uses my CaseSensitiveBindingList which I have code for later
BindingList<DGVItems> source = new CaseSensitiveBindingList<DGVItems>()
{
new DGVItems { Number = "one" },
new DGVItems{Number = "two"},
new DGVItems{Number = "Two"}
};
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = source;
dataGridView1.DataSource = bindingSource;
var index = bindingSource.Find("Number", "Two");
// Index is 2 (third item) as desired.
MessageBox.Show(number.ToString());
}
public class DGVItems
{
public string Number { get; set; }
}
And the code for the CaseSensitiveBindingList is:
public class CaseInsensitiveBindingList<T> : BindingList<T>
{
protected override int FindCore(PropertyDescriptor prop, object key)
{
string stringKey = key as string;
bool keyIsString = stringKey != null;
for (int i = 0; i < Count; ++i)
{
if (keyIsString && prop.PropertyType.IsAssignableFrom(typeof(string)))
{
if (stringKey.Equals(prop.GetValue(Items[i]).ToString(), StringComparison.CurrentCulture))
return i;
}
else
{
if (key.Equals(prop.GetValue(Items[i])))
return i;
}
}
return -1;
}
}
That code could almost certainly be improved but shows the general concept.
I need to select 5 most recent rows from cached Dataview object, is there any way to do that?
I've tried but Indexer DataColumn is empty. :
public static DataView getLatestFourActive()
{
DataTable productDataTable = getAll().ToTable();
DataColumn ExpressionColumn = new DataColumn("Indexer",typeof(System.Int32));
ExpressionColumn.Unique = true;
ExpressionColumn.AutoIncrement = true;
ExpressionColumn.AllowDBNull = false;
ExpressionColumn.AutoIncrementSeed = 0;
ExpressionColumn.AutoIncrementStep = 1;
productDataTable.Columns.Add(ExpressionColumn);
DataView productFilteredView = productDataTable.DefaultView;
productFilteredView.RowFilter = "isActive=1 and Indexer<4";
return productFilteredView;
}
getAll() returns cached DataView
thanks
I encountered the same sample above in this article, but the last post says the provided code doesn't work.
However, this article has a solution that does work, so here's the code you could use:
public static DataView getLatestFourActive() {
DataTable productDataTable = getAll().ToTable();
DataTable cloneDataTable = productDataTable.Clone();
for (int i = 0; i < 4; i++) {
cloneDataTable.ImportRow(productDataTable.Rows[i]);
}
return new DataView(cloneDataTable);
}
getALL().Take(5);