I am sure that someone has asked this before, but I am not searching for the right terms or something because I just can't seem to find what I am looking for.
I have a class Packages:
class Packages
{
string PackageID {get; set;}
string PackageName { get; set; }
}
I have a list of packages in my context.
public class TransferJobContext
{
public string ImportFile;
public string WorkSheetName;
public DataSet TransferData;
public List<Packages> Packages = new List<Packages>();
}
I have a checkedListBox on my form that is bound to a datasource. Here is the section of code where I get the values into the checkedListBox
using (var connection = my_DB.GetConnection())
{
try
{
connection.Open();
SqlDataReader rdr = null;
dt = new DataTable();
string CommandText = "SELECT ID, Name FROM TABLENAME WHERE UPPER(Import_File_Source) LIKE '%abc%' and STATUS = 1";
SqlCommand cmd = new System.Data.SqlClient.SqlCommand(CommandText, connection);
rdr = cmd.ExecuteReader();
dt.Load(rdr);
cbPackages.DataSource = dt;
cbPackages.ValueMember = "ID";
cbPackages.DisplayMember = "Name";
}
catch (Exception E)
{
MessageBox.Show(E.Message.ToString());
}
connection.Close();
}
How do I add a new Package to the list when an item is checked using the value member and displaymember of the selected items?
Edit: Ok maybe I am going about this completely wrong. Instead of telling you what I have done, I'll tell you what I would like to happen.
I am presenting my user with a checkedlistbox that has a list of names with check boxes next to them. They can select more than one. This results in me having one or more ID(s) to use in my query and name(s) to use as a description. I need to pass around with my context the one or many id/name combinations of my "Package".
What is the best what to capture the ID/Name combination of the selections the user made and pass them into my context?
First: Fetch existing Packages from your database:
public function GetPackages() as List<Package>
{
using (var connection = my_DB.GetConnection())
{
try
{
connection.Open();
SqlDataReader rdr = null;
dt = new DataTable();
string CommandText = "SELECT ID, Name FROM TABLENAME WHERE UPPER(Import_File_Source) LIKE '%abc%' and STATUS = 1";
SqlCommand cmd = new System.Data.SqlClient.SqlCommand(CommandText, connection);
var packages = new List<Package>();
using(var reader = cmd.ExecuteReader())
{
do while(reader.Read())
{
packages.Add(new Package({ID = reader.GetString(0), Name = reader.GetString(1)})
}
}
cbPackages.DataSource = packages;
cbPackages.ValueMember = "ID";
cbPackages.DisplayMember = "Name";
return packages;
}
catch (Exception E)
{
MessageBox.Show(E.Message.ToString());
return new List<Package>();
}
connection.Close();
}
}
Second:
Assign the fetched packages to the instance of your context:
yourContext.Packages = GetPackages();
Third:
Fill the CheckedListBox with your packages:
cbPackages.DataSource = yourContext.Packages;
cbPackages.ValueMember = "ID";
cbPackages.DisplayMember = "Name";
Finally: After user input, get the checkedpackages and do whatever you want with them:
foreach (Package item in checkedListBox1.CheckedItems)
{
MessageBox.Show(Package.ID);
MessageBox.Show(Package.Name);
//do whatever you want here e.g. pass it back to the context
}
Sidenote: I would suggest you to rename Packages to Package, PackageID to ID and PackageName to Name (As already proposed in the example code).
Related
If I have the following table:
canAssign
------------
1
Is there a way to add the column header text (e.g., canAssign, etc.) to the CheckedListBox as the labels that a user can check?
All answers I've found list the value as the labels, like this:
☐ 1
Instead of this:
☐ canAssign
For Example Only, If I'm using the following to list whatever value is in the canAssign column, how could I change this to list the 'canAssign' column header text?
string myString = "SELECT canAssign FROM Permissions";
using (SqlConnection myConn = new SqlConnection(globalConnectionString))
{
try {
myConn.Open();
using (SqlCommand myComm = new SqlCommand(myString, myConn))
{
SqlDataReader myReader = myComm.ExecuteReader();
while (myReader.Read()) {
checkedListBox1.Items.Add(myReader["canAssign"]);
}
}
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
Assuming the SQL query in your code snippet is to get the permissions of a specific user and display them in a CheckedListBox using the same fields names from the database.
If that sounds right, read the entry, loop to get the fields names and values through the SqlDataReader.GetName and SqlDataReader.GetBoolean methods respectively.
//For example...
var myString = "SELECT * FROM Permissions WHERE UserId = ....";
try
{
using (SqlConnection myConn = new SqlConnection(globalConnectionString))
using (SqlCommand myComm = new SqlCommand(myString, myConn))
{
myConn.Open();
using (var myReader = myComm.ExecuteReader())
if (myReader.Read())
for (var i = 0; i < myReader.FieldCount; i++)
checkedListBox1.Items.Add(myReader.GetName(i), myReader.GetBoolean(i));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
In this case I think you'd like to have custom objects in CheckedListBox.Items collection and use CheckedListBox.DisplayMember property with CheckedListBox.ValueMember
DisplayMember
Gets or sets a string that specifies a property of the objects
contained in the list box whose contents you want to display.
ValueMember
Gets or sets a string that specifies the property of the data source
from which to draw the value.
Example
public class ListBoxItem
{
public string Text { get; set; }
public string Value { get; set; }
}
checkedListBox.DisplayMember = "Text";
checkedListBox.ValueMember = "Value";
...create connection and create command logic...
command.CommandText = "SELECT * FROM Permissions";
var reader = command.ExecuteReader();
while (reader.Read()) {
// of course it would be better to cache that and go straight by indexes
for(int i = 0; i < reader.FieldCount; i++) {
var columnName = reader.GetName(i);
// some logic to humanize values like 'canDownload' to 'Can Download'
var label = getLabelFor(columnName);
var value = reader.GetBoolean(i);
checkedListBox.Items.Insert(0, new ListBoxItem(label , value));
}
}
Trying to set up a connection to my local SQL Server Express instance so that I can display columns in a listbox. Th build runs fine and I can't see errors, but there is no data in the listbox. I have tested the query and that is fine. I am using NT Authentication to the database. Any ideas where I might have gone wrong?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void customers_SelectedIndexChanged(object sender, EventArgs e)
{
string commstring = "Driver ={SQL Server}; Server = DESKTOP-5T4MHHR\\SQLEXPRESS; Database = AdventureWorks2014; Trusted_Connection = Yes;";
string connstring = "SELECT FirstName, LastName FROM Person.Person";
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(commstring, connstring);
DataSet customerDataSet = new DataSet();
customerDataAdapater.Fill(customerDataSet, "Person.Person");
DataTable customerDataTable = new DataTable();
customerDataTable = customerDataSet.Tables[0];
foreach (DataRow dataRow in customerDataTable.Rows)
{
customers.Items.Add(dataRow["FirstName"] + " (" + dataRow["LastName"] + ")");
}
}
}
I tested your code in a sample project here and I realized you passed the parameters to SqlDataAdapter constructor in a wrong order.
After changing the follow line:
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(commstring, connstring);
by
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(connstring, commstring);
the listbox was filled successfully.
Your connection string seems weird.....
Could you try using just this:
string commstring = "Server=DESKTOP-5T4MHHR\\SQLEXPRESS;Database=AdventureWorks2014;Trusted_Connection=Yes;";
Also: why are you first creating a DataSet, filling in a single set of data, and then extracting a DataTable from it?? This is unnecessarily complicated code - just use this instead:
SqlDataAdapter customerDataAdapater = new SqlDataAdapter(commstring, connstring);
// if you only ever need *one* set of data - just use a DataTable directly!
DataTable customerDataTable = new DataTable();
// Fill DataTable with the data from the query
customerDataAdapater.Fill(customerDataTable);
Update: I would really rewrite your code to something like this:
// create a separate class - call it whatever you like
public class DataProvider
{
// define a method to provide that data to you
public List<string> GetPeople()
{
// define connection string (I'd really load that from CONFIG, in real world)
string connstring = "Server=MSEDTOP;Database=AdventureWorks2014;Trusted_Connection=Yes;";
// define your query
string query = "SELECT FirstName, LastName FROM Person.Person";
// prepare a variable to hold the results
List<string> entries = new List<string>();
// put your SqlConnection and SqlCommand into "using" blocks
using (SqlConnection conn = new SqlConnection(connstring))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
conn.Open();
// iterate over the results using a SqlDataReader
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
// get first and last name from current row of query
string firstName = rdr.GetFieldValue<string>(0);
string lastName = rdr.GetFieldValue<string>(1);
// add entry to result list
entries.Add(firstName + " " + lastName);
}
rdr.Close();
}
conn.Close();
}
// return the results
return entries;
}
}
And in your code-behind, you only need to do something like this:
protected override void OnLoad(.....)
{
if (!IsPostback)
{
List<string> people = new DataProvider().GetPeople();
customers.DataSource = people;
customers.DataBind();
}
}
but I still don't understand what you were trying to when the SelectedIndexChanged event happens.....
I'm creating a list <object> and here I'm adding my data from a database.
But I totally don't know how to deal with a list <object>.
public class ClassList
{
public int Name { get; set; }
public string Birthday { get; set; }
}
private void GetClassList()
{
SqlConnection conn = new SqlConnection(GlobalVar.ConnString);
SqlCommand cmd = new SqlCommand
("SELECT * " +
"FROM Class_Data ", conn);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();
try
{
List<ClassList> ClassList = new List<ClassList>();
while (dr.Read())
{
ClassList.Add(new ClassList()
{
Name = ___?___, //what should i write here
Birthday = ___?___ //and here
});
}
}
catch{}
finally
{
dr.Close();
conn.Close();
}
}
Having been looking for lots of information but still fail to work it out.
I will be very appreciated if someone could help!
This should do it:
List<ClassList> ClassList = new List<ClassList>();
while (dr.Read())
{
ClassList.Add(new ClassList()
{
Name = (int)dr["Name"], //the name of the db column
Birthday = dr["Birthday"].ToString();
});
}
As a side note, it maybe worth altering your query from SELECT *... to just selecting the columns you require, from readability/maintenance point of view.
Also, is Name really an int seems like it could be a string.
You can also refer to the documentation:
SqlDataReader.Item Property (String)
You can use column name that are return by your database query with dr like dr["ColumnName"]
ClassList.Add(new ClassList()
{
Name = dr["NameColum"], //what should i write here
Birthday = dr["BrithColum"] //and here
});
Something like that:
// You don't use "this" in the context
// It seems, that you want to return the collected data (List<ClassList>)
private static List<ClassList> GetClassList() {
// Put IDisposable into using
using (SqlConnection conn = new SqlConnection(GlobalVar.ConnString)) {
conn.Connect();
// You want to fetch two fields only, right? Not the entire table (*)
String sql =
#"select Name,
BirthDay
from Class_Data"
using (SqlCommand cmd = new SqlCommand(sql, conn)) {
List<ClassList> result = new List<ClassList>();
using (SqlDataReader dr = cmd.ExecuteReader()) {
while (dr.Read()) {
result.Add(new ClassList() {
Name = Convert.ToString(dr[0]),
Birthday = Convert.ToDateTime(dr[1])
});
}
}
return result;
}
}
}
You can access the column values with dr["ColumnName"].
I have a method which populates my ComboBox from a DataTable:
public string populateCompanyTransSellingEntityLookUp(ref System.Windows.Forms.ComboBox Combo, string Id, Contract Contract)
{
SqlCommand _comm = new SqlCommand();
_comm.Parameters.AddWithValue("#id", Id);
_comm.CommandText = "SELECT [name] FROM dbo.fnGetList(#id) ORDER BY [name]; ";
_comm.Connection = _conn;
_comm.CommandTimeout = _command_timeout;
DataTable dt = new DataTable();
try
{
SqlDataReader myReader = _comm.ExecuteReader();
dt.Load(myReader);
Combo.DataSource = dt;
Combo.DisplayMember = "name";
foreach (DataRow dr in dt.Rows)
{
if (dr["name"].ToString() == Contract.Company_Name.ToString())
{
Combo.Text = dr["company_int_name"].ToString();
}
}
}
catch
{
MessageBox.Show("Unable to populate Company Name LookUp");
}
return "";
}
I'm passing my saved value Contract.Company_Name into the forEach loop to find my required SelectedItem from the DataTable. The ComboBox is populated with my DataTable values from Combo.Datasource =dt; but my selected item isn't being set. The code compiles without exception. If I remove Datasource = dt;, theSelectedItemis set no problem. Why is theDatasourceoverriding mySelectedItem` and is there something I've missed with my binding?
Thanks all
At first you have to set the valueMember for sure. Then you can set the selectedValue Property instead of SelectedItem. The Item is one datasource record. So in your case it would be SelectedItem = dr! But iam not sure this is working.
Try this:
Combo.SelectedItem = dr;
I would suggest to use SelectedValue, then you don't need to loop through values "manually".
Also you don't need to use "heavy-weight" DataTable where you need just a collection of string values.
private IEnumerable<string> LoadNames(string id)
{
var query = "SELECT [name] FROM dbo.fnGetList(#id) ORDER BY [name]";
using (var connection = new SqlConnection("connectionString")
using (var command = new SqlCommand(query, connection)
{
// 36 is the size of the VarChar column in database(use your value)
command.Parameters.Add("#id", SqlDbType.VarChar, 36).Value = id;
connection.Open();
using (var reader = command.ExecuteReader())
{
var names = new List<string>();
while(reader.Read())
{
names.Add(reader.GetString(0));
}
return names;
}
}
}
public void Populate(ComboBox combobox, string id, Contract contract)
{
combobox.DataSource = LoadNames(id);
combobox.SelectedValue = contract.Copmpany_Name.ToString();
}
Few things to notice:
Dispose all objects which dealing with external resources (SqlConnection, SqlCommand and SqlDataReader)
Create SqlParameter with precise information about the type, for strings is important to provide size of the column in database. This information will improve SQL query performance on server side.
Don't pass combobox as a reference, populate method does not create new instance but only consume the given ComboBox instance.
Thank you for the help, I edited the code given that my problem was much more trivial.
public string populate_comboBox(ref System.Windows.Forms.ComboBox Combo)
{
SqlCommand _comm = new SqlCommand();
//edited for a simple one column sql query
_comm.CommandText ="SELECT [Column] FROM dbo.SQL_Table ORDER BY [Column];";
//MUST open sql connection to DB
SqlConnection conn = new SqlConnection(global_DB_String_Connection);
conn.Open();
_comm.Connection = conn;
DataTable dt = new DataTable();
try
{
SqlDataReader myReader = _comm.ExecuteReader();
dt.Load(myReader);
Combo.DataSource = dt;
Combo.DisplayMember = "ColumnName";
foreach (DataRow dr in dt.Rows)
{
//populates the combo box with query results
Combo.Text = dr["ColumnName"].ToString();
}
}
catch
{
Console.WriteLine("ComboBox Populate method has failed! ");
}
conn.Close();
return "";
}
Hopefully i don't sound confusing but i am not sure if what i am trying to get at is possible.
I have a select statement to get name, id, guid. I am setting the display to name and the value to Id for each combobox. Is there a way that i could also assign the guid to the combo box so that i could use it in my winforms app?
here is what i have for select statement:
private void secondChild_drp_SelectedIndexChanged(object sender, EventArgs e)
{
string secondChildId = secondChild_drp.SelectedValue.ToString();
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
using (SqlDataAdapter sda = new SqlDataAdapter("SELECT ... WHERE em.ChildID = (" + secondChildId + ")", conString))
{
DataTable dt = new DataTable();
sda.Fill(dt);
thirdChild_drp.ValueMember = "ID";
thirdChild_drp.DisplayMember = "DisplayName";
thirdChild_drp.DataSource = dt;
}
}
cmd.CommandText="StoreProcName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ChildID", secondChildId);
cmd.Connection = con2;
con2.Open();
reader = cmd.ExecuteReader();
var guid = reader.ToString();
reader.Close();
con2.Close();
}
right now when i run this it tells me reader = cmd.ExecuteReader(); has Procedure or function StoreProcName has too many arguments specified.
i just want to get the guid associated with the id i passed in.
You can get the guid from your datatable as follows where yourselectedid is the combobox selecteditem id.
var results = from row in dt.AsEnumerable()
where row.Field<int>("ID") == yourselectedid
select row;
now from results you can get all the desired columns you want
Basically the same answer as I already posted here:
You could define a simple object which you are filling from your data base query:
public class Item
{
public int ID { get; set; }
public string DisplayName { get; set; }
public Guid Guid{ get; set; }
}
Your implementation could look something like this (some mockup data):
listBox1.DataSource = items;
listBox1.DisplayMember = "DisplayName";
listBox1.ValueMember = "ID";
Then based on the value you selected, you can query through your items and get the item:
var key = (int)listBox1.SelectedValue;
foreach (var existingItem in items)
{
if (existingItem.Key == key)
{
//woohoo got it!
Debug.Print(existingItem.Guid.ToString())
}
}
you can put both of the value in the value member, separated by whichever character for separator like : "12;0000-000-0000" then separate again the Value Menber with a String.Split.