Error When Looping Through DataSet and Inserting into ListBox - c#

This is a windows forms application. I have a class Program.cs and a form DeployerConsole.cs with a ListBox on it. I am attempting to loop through the results from the SQL query. I am having trouble and getting a 'Object reference not set to an instance of an object.' error when I try to access the data and insert it into my listbox on the form.
EDIT: The SQL Query is completing successfully and the Console.WriteLine is outputting to the output window properly with the correct data.
static void LoadServers()
{
DeployerConsole DC = (DeployerConsole)Application.OpenForms["DeployerConsole"];
//DeployerConsole DC = new DeployerConsole();
SqlConnection myConnection = new SqlConnection("server=XXX; database=XXX; uid=XXX; pwd=XXX;Integrated Security=true;Connection Lifetime=5;Trusted_Connection=yes;");
myConnection.Open();
DataSet ds = new DataSet();
SqlCommand myCommand = new SqlCommand("SELECT ServerName FROM DeployServers", myConnection);
SqlDataAdapter adapter = new SqlDataAdapter(myCommand);
adapter.Fill(ds);
DataTable dt = ds.Tables[0];
foreach (DataRow dr in dt.Rows)
{
DC.listBox1.Items.Add(dr["ServerName"].ToString());
Console.WriteLine(dr["ServerName"].ToString());
}
}
EDIT: Added Screenshot
Anyone have any suggestions or provide guidance as to what I am doing wrong?
EDIT (ANSWER): Well, I moved the code from the class to the form. No problems accessing the listBox now. However, I still would like to know the solution to this.

It might be worth a try (just for testing purposes) to try:
if(DC.listBox1 != null)
{
DC.listBox1.Items.Add(dr["ServerName"].ToString());
}
That could give you a clue, if which you might need to make sure someplace listBox1 is instantiated.
DC.listBox1 = new ListBox();
EDIT
It might be that DC is not being correctly passed by reference to the static method.
It might be better to change the signature of the Method to accept the form.
static void LoadServers(Form form)
{
...
form.listBox1.Items.Add(...)
... etc.
}
and call it assuming from the form:
Helper.LoadServers(this);

Your problem is probably caused by this line of code:
DeployerConsole DC = (DeployerConsole)Application.OpenForms["DeployerConsole"];
I suspect the OpenForms property is returning null because you have not explicitly set the name of your form (e.g. form.Name = "DeployerConsole";).

Related

How to load the datagridview using OOP C#

I am a beginner at C# and .NET oop concepts. I want to load the datagridview. I don't know how to pass the data. What I tried so far I attached below.
I created a class std
public void get()
{
SqlConnection con = new SqlConnection("server =.; initial catalog=testdb; User ID=sa; Password=123");
string sql = "select * from std";
con.Open();
SqlCommand cm = new SqlCommand(sql, con);
SqlDataReader dr = cm.ExecuteReader();
while ( dr.Read())
{
string stname = dr["st_name"].ToString();
string nicnum = dr["nic"].ToString();
}
con.Close();
}
Form: I am getting data like this way
std ss = new std();
ss.get();
dataGridView1.Rows.Clear();
If I wrote like this way how to pass data into the datagridview columns? I am stuck in this area
It's easier like this:
public void FillGrid()
{
var dt = new DataTable();
var da = new SqlDataAdapter("select * from std", "server =.; initial catalog=testdb; User ID=sa; Password=123");
da.Fill(dt);
dataGridView1.DataSource = dt;
}
but if you're going to use such a low level method of database access you should consider adding a DataSet type of file to your project; visual studio will write all this code and more for you with a few mouse clicks, and it makes a good job of creating tables and adapters that are a lot easier to work with
you have made multiple mistakes. First you read data wirh dataraeader and in every iteration define two stname and nimnum variables like. So when loop ends variables are destroyed. You have to define data table and read data by dataraeader and and add them to it row by row. Or read by sqldataadapter and read it immediately and pass to datatable object.Finnaly you pass datatable as return object of function. Use this vala as datasource of datagridview property if I'm not wrong.

An error occurred while receiving DataTable in wcf service response

I am developing a windows form application in c#. My database is handled in a wcf application. In my wcf application I have a class called lecturer which has a method called view lecturers() as follows. My purpose is to view the lecturers table in a grid view.
public DataTable viewLec()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["resourceAlloc"].ToString());
DataTable dt = new DataTable();
string vw = "select * from lecturers";
SqlCommand cmd = new SqlCommand(vw,con);
SqlDataAdapter adp = new SqlDataAdapter(cmd);
adp.Fill(dt);
return dt;
}
In my IService1.cs:
[OperationContract]
DataTable viewLecturer();
Service1.svc.cs:
public DataTable viewLecturer()
{
Lecturer lec = new Lecturer();
return lec.viewLec();
}
in my windows form application button click event,
private void button2_Click(object sender, EventArgs e)
{
Service1Client obj = new Service1Client();
dataGridView1.DataSource = obj.viewLecturer();
}
When I click the view button the above error occurs, I cannot understand why?
I don't know the exact error of your code, but first thing I want to mention is that using DataTable object as your Data Contract is not the best idea as it contains certain amount of extra data which usually is not consumed by the end applications. But anyway, in your particular case WCF will not be able to serialize your your object as it will not have table name which is mandatory for this class to perform serialization. Try to follow this way:
DataTable dt = new DataTable();
// Must set name for serialization to succeed.
dt.TableName = "lecturers";
I don't see the actual error you have (you should post it to make your answer more clear), but at least this will help you to avoid serialization error.

Updating a dataset changes with data adapter does not seem to work properly

I wanted to update my dataset changes to my database, so I used this sort of code:
SqlCommandBuilder mySqlCommandBuilder = new SqlCommandBuilder(sqladap);
sqladap.Update(ds, TableName);
While it works properly I have used this code for another dataset in my project but the second one does not work. I traced this code and saw the rows of the dataset. It contains both last fetched rows and new rows but the SQLDataAdapter updates any data and also it does not throw an error.
here is the full code:
public static SqlDataAdapter AdapterStoredProcedure(string sp_Name, object obj)
{
ClsEventLogs EventLogs = new ClsEventLogs();
try
{
SqlConnection connection = SQLDBConnection();
SqlDataAdapter sqladap = new SqlDataAdapter(sp_Name, connection);
sqladap.SelectCommand.CommandType = CommandType.StoredProcedure;
if (obj != null)
{
Type t = obj.GetType();
string str = string.Empty;
System.Reflection.FieldInfo[] fields = t.GetFields();
foreach (System.Reflection.FieldInfo field in fields)
{
sqladap.SelectCommand.Parameters.Add(new SqlParameter(field.Name, SqlDbType.VarChar, 200));
sqladap.SelectCommand.Parameters[field.Name].Value = field.GetValue(obj).ToString();
}
}
return sqladap;
}
catch(Exception er)
{
EventLogs.Eventlog("clsDataStore : ExecuteStoredProcedure", er.Message, ClsEventLogs.EventType.etCriticalError, false);
return null;
}
}
// Creating Adapter
SqlDataAdapter dAdap = null;
DataSet ds = new DataSet();
dAdap = clsDataStore.AdapterStoredProcedure("sp_SelectTbl_Client", null);
dAdap.Fill(ds, "tbl_client");
//here is where i'm Updating the dataset
SqlCommandBuilder mySqlCommandBuilder = new SqlCommandBuilder(sqladap);
sqladap.Update(ds, TableName);
You'll have to look (Debugger) at the generated SQL Update/Insert statements. Most likely they are flawed or even empty.
The CommandBuilder is extremely limited, it only deals with very simple SELECT a, b FROM table statements.
You will probably find that the SP that doesn't work contains a JOIN, computed column or something like that.
Best course: provide your own Update statements or SPs
To ask the dumb question: did you tell your adapter to commit the changes after calling the Update method?
EDIT: OK, now that you've posted your code, I have to ask another dumb question: what are you looking at to determine if the update worked? Are you connecting to a remote database right now, or a test database in the project? If it's the latter, then if you are rebuilding each time (something I'm in the habit of doing) then your working copy of the database (in the \bin directory) gets blown away and replaced with a fresh copy from wherever it's referenced from in the project. That assumes, of course, that you're using an embedded DB (like MSSQLCE).

Sqldataapter advice

At present i have a the following code populating a datagridview showing the user account information on our system. What i want to do do is have a checkbox on the datagridview for the option "accountenabled" and a update button at the bottom of the form so it will update all users that have had changes made against them. I am currently pulling the data back using an sqldatareader however from what i have read i need to use a sqldataadapter. I`ve created the column names on the datagridview and the reader is currently pulling everything back correctly.
Could someone please point me in the right direction of doing this with an sqldatadapter?
Thanks
public UserAdmin()
{
InitializeComponent();
//Load user list
// Locals
Functionality func = new Functionality();
SqlConnection supportDB = null;
SqlCommand CheckUser = null;
SqlDataReader rdr;
DataSet ds = new DataSet();
DataTable dt = new DataTable();
string User = System.Environment.UserName.ToString();
string spName = "gssp_ShowAllUsers";
try
{
using (supportDB = new SqlConnection(GSCoreFunc.ConnectionDetails.getConnectionString(ConnectionType.SupportDB)))
{
using (CheckUser = new SqlCommand(spName, supportDB))
{
// Set the command type
CheckUser.CommandType = CommandType.StoredProcedure;
// Populate the parameters.
CheckUser.Parameters.Add(func.CreateParameter("#spErrorID", SqlDbType.Int, ParameterDirection.Output, DBNull.Value));
// Open the connection and populate the reader with the SP output
supportDB.Open();
rdr = CheckUser.ExecuteReader();
if (CheckUser.Parameters["#spErrorID"].Value != null)
{
throw new InvalidOperationException();
}
// If the data reader has rows display output on label
if (rdr.HasRows)
{
//Output values
while (rdr.Read())
{
//Bind to data table
dgvUsers.Rows.Add(rdr["agentID"].ToString(), rdr["createdon"].ToString(), rdr["firstname"].ToString(), rdr["lastname"].ToString(), rdr["username"].ToString(), rdr["emailaddress"].ToString(), rdr["Departments"].ToString(), rdr["accountenabled"].ToString(), rdr["AgentAccountLevel"].ToString());
}
}
// Close reader and connection.
rdr.Close();
supportDB.Close();
}
}
}
catch (Exception ex)
{
//Show error message
string error = ex.ToString(); //Real error
string FriendlyError = "There has been error loading the user list"; // Error user will see
GSCoreFunc.ShowMessageBox.msgBoxErrorShow(FriendlyError);
//Log error to ExceptionDB
GSCoreFunc.ReportException.reportEx(GSCoreFunc.ApplicationInformation.ApplicationName, error, FriendlyError, GSCoreFunc.ApplicationInformation.ComputerName, GSCoreFunc.ApplicationInformation.OperatingSystem, GSCoreFunc.ApplicationInformation.screenSize, GSCoreFunc.ApplicationInformation.IPAdddress, GSCoreFunc.ApplicationInformation.domainName);// Pass error to GSCoreFunc to log to the ExceptionDB
}
}
private void btClose_Click(object sender, EventArgs e)
{
//Close window
Close();
}
}
}
There is nothing wrong with using the SqlDataReader. The SqlDataAdapter is a higher level api that allows you to iterate through an SqlDataReader and store a copy of the results in a DataTable or a DataSet. This copy can then be used as the data source for your DataGridView.
One thing I would change with your code would be to use data binding instead of generating each row manually. If you set the DataSource property of the grid to either your SqlDataReader or to a DataTable filled by an SqlDataAdapter and then call the grids DataBind() method the grid should be filled automatically with your data.
To control the columns you would make sure your query only returns the required columns, and you would define the column setup in your aspx-file.
Using data binding is generally an easier and more flexible approach, so you should consider using that instead.
Look at this code
Initialize a sql adapter and fill with data source . Use a connection string other than using sql data source because it would be easy for customizing. :)

c# windows forms / basic data grid

One of the problems I am having with c# is that there seems to be so much information online that I am having trouble finding the right answer to the most basic of questions.
I am trying to do something simple:
I have a button, I click it, it queries the database and populates a datagrid on my windows form.
private void button1_Click(object sender, EventArgs e)
{
SqlConnection c = new SqlConnection("Data Source = (local); Integrated Security = true; Initial Catalog = pubs; ");
c.Open();
// 2
// Create new DataAdapter
SqlCommand cmd = c.CreateCommand();
cmd.CommandText = #" SELECT * FROM Authors ";
SqlDataReader reader = cmd.ExecuteReader();
dataGridView1.DataSource = reader;
dataGridView1.DataBind();
}
Error 1 'System.Windows.Forms.DataGridView' does not contain a definition for 'DataBind' and no extension method 'DataBind' accepting a first argument of type 'System.Windows.Forms.DataGridView' could be found.....
I am probably missing a "using directive" but which one? Multiple Google searches tell me how to bind a Yahoo RSS Feed to a gridview or provide various obscure details on "using directives".
Maybe I am using the SqlDataReader incorrectly. Should I be using SqlAdapter instead? What happened to all the good basic tutorials online for windows c# forms? A few months ago I found a couple great tutorials, but they seem to have lost their pageranking and I cannot find them anymore using basic google searches.
You're not missing a using directive; it's just that the WinForms DataGridView doesn't have a DataBind method. Just assigning DataSource is enough to get the binding to happen; you don't need to call a method as well.
However, I don't think you can assign a SqlDataReader as the DataSource. According to the DataSource property documentation in MSDN, the DataSource must be an IList, an IListSource, an IBindingList or an IBindingListView. You will probably instead need to load the data into a DataTable or DataSet (or an object data source populated using an object-relational mapper), and use that as the DataSource.
Try this instead:
using (SqlConnection conn = new SqlConnection("your connection string"))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(#"SELECT * FROM Authors", conn))
{
using (SqlDataAdapter adap = new SqlDataAdapter(cmd))
{
DataTable dt = new DataTable();
adap.Fill(dt);
dataGridView1.DataSource = dt;
}
}
}
The DataGridView does not have a DataBind() method because it doesn't need one. Setting the DataSource property handles the binding for you. The using() blocks will automatically close and dispose of everything for you as well.
Note: you should replace "your connection string" with a valid connection string. I left yours out of my sample to avoid the horizontal scrollbars, and I'm not sure yours is valid anyway. You may get a runtime error when you run the code using your connection string. www.connectionstrings.com is a great resource for figuring out a valid connection string.
Update: instead of the nested using() blocks, you can also do it like this:
using (SqlConnection conn = new SqlConnection("..."))
using (SqlCommand cmd = new SqlCommand(#" SELECT * FROM Authors", conn))
using (SqlDataAdapter adap = new SqlDataAdapter(cmd))
{
conn.Open();
DataTable dt = new DataTable();
adap.Fill(dt);
dataGridView1.DataSource = dt;
}
I prefer the nested style, but it's "half of one, six dozen of the other" to me. Typically, I would encapsulate code like this into a class (called "DataGetter" or whatever) with a static method like:
public static DataTable GetData(string query)
{
// do all the connecting and adapting and filling and so forth
}
so that the code in your button click would be as simple as:
dataGridView1.DataSource = DataGetter.GetData("SELECT * FROM AUTHORS");
However, I would not do this in any performance-critical section of my code, since you sometimes want to keep a SqlCommand object (and its SqlParameter collection) around between calls. You do not need to keep SqlConnection objects around between calls, thanks to connection pooling (in fact, you don't want to keep them around under any circumstances).

Categories