Showing posts with label .Net Framework. Show all posts
Showing posts with label .Net Framework. Show all posts

Monday, 1 June 2009

Copying a DataGridViewRow to another DataGridView Control

Sometimes a simple task can be very tricky. Today I was trying to make a copy of DataGridView to another DataGridView, in the traget DataGridView I need to delete a few rows and possibly add a few new DataGridViewColumn(s), all these changes must have no impact whatsoever on the Original DataGridView object. Because of the nature of C#, object is passed by reference. So I cannot do things like DataGridView dgv_copy = dgv_original if I want to make some changes in the second DataGridView without affecting the original one.

What should I do? Firstly I need to create columns first, populate the DataGridViewColumns from the original to the new one. This is very straight forward, however when it comes to copy the rows. I came across a problem. The DataGridViewRow clone method does not work as expected. The Clone method copies the row and its property values, but does NOT copy the cell values that the row contains. So we have to write some code to copy the cell values. Please find the working example below and feel free to let me know should you have any queries.

private DataGridView CopyDataGridView(DataGridView dgv_org)
{
DataGridView dgv_copy = new DataGridView();
try
{
if (dgv_copy.Columns.Count == 0)
{
foreach (DataGridViewColumn dgvc in dgv_org.Columns)
{
dgv_copy.Columns.Add(dgvc.Clone() as DataGridViewColumn);
}
}

DataGridViewRow row = new DataGridViewRow();

for (int i = 0; i < dgv_org.Rows.Count; i++)
{
row = (DataGridViewRow)dgv_org.Rows[i].Clone();
int intColIndex = 0;
foreach (DataGridViewCell cell in dgv_org.Rows[i].Cells)
{
row.Cells[intColIndex].Value = cell.Value;
intColIndex++;
}
dgv_copy.Rows.Add(row);
}
dgv_copy.AllowUserToAddRows = false;
dgv_copy.Refresh();

}
catch (Exception ex)
{
cf.ShowExceptionErrorMsg("Copy DataGridViw", ex);
}
return dgv_copy;
}

Dynamically display tooltips when mouse hover a DataGridViewCell in WinForm application

In one of my recent projects, a customer asked me to provide a dynamic tool tip depending on the DataGridViewCell that user have his mouse hovered. For a Windows Forms DataGridView, you can handle the dataGridView1.CellToolTipTextNeeded event and dynamically provide the tip text there.

dataGridView1.CellToolTipTextNeeded += new DataGridViewCellToolTipTextNeededEventHandler(data GridView1_CellToolTipTextNeeded);
void dataGridView1_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
{
e.ToolTipText = string.Format("tip for row {0}, col {1}", e.RowIndex, e.ColumnIndex);
}

Run the application, you would see a similar screen shot as below:

Thursday, 7 May 2009

How to Compare two DataTables in ADO.net

Sometimes it’s very useful to compare two DataTables and return the different records to a third DataTable. I came across this when I needed to handle my own data concurrency control. Basically my logic is:

- Populate a DataTable of a DataSet and Copy the content of the DataTable to another DataTable immediately after this. (For example we populate a DataTable A and then make a copy to DataTable B.)
- When user update the DataTable A in my application, the event handler firstly populate to a DataTable C from the database.
- Comparing the DataTable C with the DataTable B, if they are same means underlying data hasn’t been changed, then proceed the update otherwise user can choose either to overwrite the data or cancel the operation.

Unfortunately you can’t do a straight comparison of two DataTables. For instance if you write something like: DataTable 1 == DataTable2 or DataTable1.GetHashCode() == DataTable2..GetHashCode() or DT1.Equals(DT2), none of this would work. Below is the code I am using to compare to DataTables, pretty self-explanatory. Hopefully you find it helpful.

private void button1_Click(object sender, EventArgs e)
{
// Something to do with the Initialization of the FirstDataTable and SecondDataTable

DataTable dt;
dt = getDifferentRecords(FirstDataTable, SecondDataTable);

if (dt.Rows.Count == 0)
MessageBox.Show("Equal");
else
MessageBox.Show("Not Equal");
}

#region Compare two DataTables and return a DataTable with DifferentRecords
public DataTable getDifferentRecords(DataTable FirstDataTable, DataTable SecondDataTable)
{
//Create Empty Table
DataTable ResultDataTable = new DataTable("ResultDataTable");

//use a Dataset to make use of a DataRelation object
using (DataSet ds = new DataSet())
{
//Add tables
ds.Tables.AddRange(new DataTable[] { FirstDataTable.Copy(), SecondDataTable.Copy() });

//Get Columns for DataRelation
DataColumn[] firstColumns = new DataColumn[ds.Tables[0].Columns.Count];
for (int i = 0; i < firstColumns.Length; i++)
{
firstColumns[i] = ds.Tables[0].Columns[i];
}

DataColumn[] secondColumns = new DataColumn[ds.Tables[1].Columns.Count];
for (int i = 0; i < secondColumns.Length; i++)
{
secondColumns[i] = ds.Tables[1].Columns[i];
}

//Create DataRelation
DataRelation r1 = new DataRelation(string.Empty, firstColumns, secondColumns, false);
ds.Relations.Add(r1);

DataRelation r2 = new DataRelation(string.Empty, secondColumns, firstColumns, false);
ds.Relations.Add(r2);

//Create columns for return table
for (int i = 0; i < FirstDataTable.Columns.Count; i++)
{
ResultDataTable.Columns.Add(FirstDataTable.Columns[i].ColumnName, FirstDataTable.Columns[i].DataType);
}

//If FirstDataTable Row not in SecondDataTable, Add to ResultDataTable.
ResultDataTable.BeginLoadData();
foreach (DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r1);
if (childrows == null || childrows.Length == 0)
ResultDataTable.LoadDataRow(parentrow.ItemArray, true);
}

//If SecondDataTable Row not in FirstDataTable, Add to ResultDataTable.
foreach (DataRow parentrow in ds.Tables[1].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r2);
if (childrows == null || childrows.Length == 0)
ResultDataTable.LoadDataRow(parentrow.ItemArray, true);
}
ResultDataTable.EndLoadData();
}

return ResultDataTable;
}
#endregion

Wednesday, 29 April 2009

Delete rows from a DataTable

When I tried to delete DataRows from a DataTable based on some conditions, I wrote the code as below but receive an InvalidOperationException complaining {"Collection was modified; enumeration operation might not execute."}

DataColumn dc = dsData.Tables["tbl"].Columns["order_qty"];
foreach (DataRow dr in dsData.Tables["tbl"].Rows)
{
if (dr[dc].ToString() == "0")
dsData.Tables["tbl"].Rows.Remove(dr);
}

Then I changed my code to:

DataColumn dc = dsData.Tables["tbl"].Columns["order_qty"];
foreach (DataRow dr in dsData.Tables["tbl"].Rows)
{
if (dr[dc].ToString() == "0")
dr.Delete();
}

Everything works fine. Then I went to MSDN and found the explanation of difference between using Delete and Remove method on data table:

There are two methods you can use to delete a DataRow object from a DataTable object: the Remove method of the DataRowCollection object, and the Delete method of the DataRow object. While the Remove method deletes a DataRow from the DataRowCollection, the Delete method only marks the row for deletion. The actual removal occurs when the application calls the AcceptChanges method. By using Delete, you can programmatically check which rows are marked for deletion before actually removing them. When a row is marked for deletion, its RowState property is set to Deleted.

If a row is marked for deletion and you call the AcceptChanges method of the DataTable object, the row is removed from the DataTable. In contrast, if you call RejectChanges, the RowState of the row reverts to what it was before being marked as Deleted.

Obviously my first example won’t work because I used the Remove method which deletes a DataRow from the DataRowCollection within a foreach loop.

Friday, 17 April 2009

How to Hide Rows from DataGridView in WinForm Application?

When you see the title, you may wonder why I am writing this, this is so obvious, we can easily achieve this by writing something like:

foreach (DataGridViewRow dgvr in MyDataGridView.Rows)
{
if (string.IsNullOrEmpty(dgvr.Cells["sales"].Value.ToString()))
{
dgvr.Visible = false;
}
}

However if you do this, you are more likely to get the error:
InvalidOperationException,
Row associated with the currency manager's position cannot be made invisible.

Why? Because you cannot make modifications to a row at runtime which is bound to a DataSource, unless you suspend the binding on all rows using CurrencyManager object like code shows below:

CurrencyManager cm = (CurrencyManager)BindingContext[dgvBulkSheetDtl.DataSource];
foreach (DataGridViewRow dgvr in MyDataGridView.Rows)
{
if (string.IsNullOrEmpty(dgvr.Cells["sales"].Value.ToString()))
{
cm.SuspendBinding();
dgvr.Visible = false;
}
}

Simple isn’t it? One thing you need to be aware is that if your DataGridView allows user to sort the columns, then you have to hide the rows again because the hidden rows will show up again. In this case, what you probably can do is to filter the data out from your data source.

Implement MSChart in a Windows Form Application

In my previous post, I have demonstrated step by step installing MSChart controls, a fantastic tool to generate amazing Charts in both Winform and ASP applications, on Visual Studio 2008. Now it’s time to show some working examples. Using MSChart to display a graph from Database data is very straight forward, the key is the syntax of binding data to a chart control. My demo is tested under Oracle 10 R2 and Visual Studio 2008.

First of all we need create a demo table, let’s say we want to compare the Actual Sales vs Forecast.

create table demo
(
sku number,
wcdate date,
actual number,
forecast number,
constraint pk01 primary key (sku, wcdate)
)
/
insert into demo values (24, to_date('08/03/2009', 'dd/mm/yyyy'), 3020, 3200);
insert into demo values (24, to_date('15/03/2009', 'dd/mm/yyyy'), 3131, 3200);
insert into demo values (24, to_date('22/03/2009', 'dd/mm/yyyy'), 2937, 2500);
insert into demo values (24, to_date('29/03/2009', 'dd/mm/yyyy'), 2842, 2500);
insert into demo values (24, to_date('05/04/2009', 'dd/mm/yyyy'), 2988, 2500);
/

Secondly we create a new WinForm application in VS 2008, drag a Char control from tool box and place it at the top section of the form.

Next drag another DataGridView control and place it at the bottom of the form. We will then have something like the screenshot below.

Press F7 to go to the code view, we can then write some code to pull the data from database and bind the data to the chart control:

using System;
using System.Data;
using System.Windows.Forms;
using System.Data.OracleClient;

namespace ChartDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

DataSet dsdata = new DataSet();

// Populate public DataSet
private DataSet PopulateDataTable()
{
string connectionString = "Data Source=orcl;Persist Security Info=True; "
+ "User ID=scott;Password=xxxxx;Unicode=True";

string queryString = "select * from demo";

OracleConnection connection = new OracleConnection(connectionString);
OracleCommand command = new OracleCommand(queryString, connection);
OracleDataAdapter da = new OracleDataAdapter(command);

try
{
connection.Open();
if (!dsdata.Tables.Contains("chart"))
dsdata.Tables.Add("chart");
da.Fill(dsdata, "chart");
}
catch (OracleException oex)
{
throw new Exception(oex.Message);
}
finally
{
connection.Close();
}
return dsdata;
}

// Load the data to a DataGridView
private void LoadDGV()
{
dataGridView1.DataSource = PopulateDataTable();
dataGridView1.DataMember = "chart";
}

// Render the chart
private void LoadFcstVsActualChart()
{
DataView dv = new DataView(dsdata.Tables["chart"]);
chart1.Series["Actual"].Points.DataBindXY(dv, "wcdate", dv, "actual");
chart1.Series["Forecast"].Points.DataBindXY(dv, "wcdate", dv, "forecast");
}

//Form load event
private void Form1_Load(object sender, EventArgs e)
{
LoadDGV();
LoadFcstVsActualChart();
}
}
}

I believe above code is quite self-explanatory, firstly we created a DataSet and populate the data to the DataSet, then we binded the DataView to the Chart control, at the end we put all methods into Form load event to load data to DataDridView and generate the Chart afterwards. The import thing to remember is the syntax of binding data to a chart.

// Render the chart
private void LoadFcstVsActualChart()
{
DataView dv = new DataView(dsdata.Tables["chart"]);
chart1.Series["Actual"].Points.DataBindXY(dv, "wcdate", dv, "actual");
chart1.Series["Forecast"].Points.DataBindXY(dv, "wcdate", dv, "forecast");
}

There are loads of different ways we can make our chart prettier to attract more eyeballs. For example you can change the background color or border style in the properties of the chart.

Or you can change the Chart Display type in Series collection. To see the best practice, please refer to Samples Environment for Microsoft Chart Controls from Microsoft

Now you can see how simple is that to use MSChart controls. A few lines of code can do the trick, I have tried MSChart in my last 2 projects, our customers who are so used to traditional dull business applications just love it. I hope you find it useful as well. Let me know if there is any problem or questions.

Friday, 3 April 2009

Step by Step installing MS Chart Controls on Visual Studio 2008

Generating wonderful charts in .Net application sometimes can easily get customers blown away. Microsoft purchased some products from Dundas Company about a year and a half ago and implementing theirs charts technology into the products. And from last September they give us the free charting controls (both Web and WinForms) for use in our .NET 3.5 applications.

Step 1: To get start you need to download and install:
Microsoft Chart Controls for Microsoft .NET Framework 3.5 and Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008.

Step 2: Once you have the installation files downloaded, install MSChart.exe first, as the add-on requires this to be installed. Both are quick installs, and should take no more than a few minutes, so when both have been successfully installed to your machine, you can start up Visual Studio.

Step 3: create a new Web or WinForm Application, and now to get the new control into our toolbox, we can right-click on a blank area of it and select Add Tab. Name it something like MSChart:



Step 4, right-click in the new tab and select Choose Items...



We should then see a dialog box like this:



Step 5: Click the Browse button and navigate to the Program Files\Microsoft Chart Controls\Assemblies folder. Here you want to add both the Windows.Form and the Web DLLs. Once they're added, they will be available to select in the list box:



So once they're added, and checked, they should be available in our toolbox:



After you’ve done the configuration, I strongly recommend you to download the Samples Environment for Microsoft Chart Controls from Microsoft and read the docs: Microsoft Chart Controls for .NET Framework Documentation.

In my next post, I will write a quick demo on how to implement MSChart in a Windows Form Application to display a graph from database data.

Friday, 6 March 2009

Export Data from DataGridView to Excel in C# Windows Forms

A very common requirement as a .Net developer would receive from customer is to export the data from DataGridView to excel. As developers we don’t particularly like Excel because it lacks of centralized control, poor metadata awareness. awkward email/shared network sharing etc. But we have to admit Excel is a great tool and our customers are so used to it, this is not something we should ban customers from using, on the contrary we should help customers to use excel with high quality data. Here is where this requirement coming from. I have been researching on the internet for a stable solution, however I didn’t find one. I found one from here which looks very good but contains a few bugs, I updated the code to make it fully work. It works fine in my environment, feel free to comment if you see a problem.

using System;
using System.Windows.Forms;
using System.Reflection;


namespace Demo
{
class CommonFunctions
{
/// Exports a passed datagridview to an Excel worksheet.
/// If captions is true, grid headers will appear in row 1.
/// Data will start in row 2.
public static void ExportToExcel(DataGridView datagridview, bool captions)
{
object objApp_Late;
object objBook_Late;
object objBooks_Late;
object objSheets_Late;
object objSheet_Late;
object objRange_Late;
object[] Parameters;
string[] headers = new string[datagridview.ColumnCount];
string[] columns = new string[datagridview.ColumnCount];

int i = 0;
int c = 0;
int t = 0;
int j = 0;


try
{
for (c = 0; c <= datagridview.ColumnCount - 1; c++)
{
headers[c] = datagridview.Rows[0].Cells[c].OwningColumn.Name.ToString();
if (c < 26)
{
t = c;
i = t + 65;
columns[c] = Convert.ToString((char)i);
}
else
{
t = c % 26;
j = c / 26 - 1;
j = j + 65;
i = t + 65;
columns[c] = Convert.ToString((char)j) + Convert.ToString((char)i);
}
}
// Get the class type and instantiate Excel.
Type objClassType;
objClassType = Type.GetTypeFromProgID("Excel.Application");
objApp_Late = Activator.CreateInstance(objClassType);
//Get the workbooks collection.
objBooks_Late = objApp_Late.GetType().InvokeMember("Workbooks",
BindingFlags.GetProperty, null, objApp_Late, null);
//Add a new workbook.
objBook_Late = objBooks_Late.GetType().InvokeMember("Add",
BindingFlags.InvokeMethod, null, objBooks_Late, null);
//Get the worksheets collection.
objSheets_Late = objBook_Late.GetType().InvokeMember("Worksheets",
BindingFlags.GetProperty, null, objBook_Late, null);
//Get the first worksheet.
Parameters = new Object[1];
Parameters[0] = 1;
objSheet_Late = objSheets_Late.GetType().InvokeMember("Item",
BindingFlags.GetProperty, null, objSheets_Late, Parameters);

if (captions)
{
// Create the headers in the first row of the sheet
for (c = 0; c <= datagridview.ColumnCount - 1; c++)
{
//Get a range object that contains cell.
Parameters = new Object[2];
Parameters[0] = columns[c] + "1";
Parameters[1] = Missing.Value;
objRange_Late = objSheet_Late.GetType().InvokeMember("Range",
BindingFlags.GetProperty, null, objSheet_Late, Parameters);
//Write Headers in cell.
Parameters = new Object[1];
Parameters[0] = headers[c];
objRange_Late.GetType().InvokeMember("Value", BindingFlags.SetProperty,
null, objRange_Late, Parameters);
}
}

// Now add the data from the grid to the sheet starting in row 2
for (i = 0; i < datagridview.RowCount; i++)
{
for (c = 0; c <= datagridview.ColumnCount - 1; c++)
{
//Get a range object that contains cell.
Parameters = new Object[2];
Parameters[0] = columns[c] + Convert.ToString(i + 2);
Parameters[1] = Missing.Value;
objRange_Late = objSheet_Late.GetType().InvokeMember("Range",
BindingFlags.GetProperty, null, objSheet_Late, Parameters);
//Write Headers in cell.
Parameters = new Object[1];
Parameters[0] = datagridview.Rows[i].Cells[headers[c]].Value.ToString();
objRange_Late.GetType().InvokeMember("Value", BindingFlags.SetProperty,
null, objRange_Late, Parameters);
}
}

//Return control of Excel to the user.
Parameters = new Object[1];
Parameters[0] = true;
objApp_Late.GetType().InvokeMember("Visible", BindingFlags.SetProperty,
null, objApp_Late, Parameters);
objApp_Late.GetType().InvokeMember("UserControl", BindingFlags.SetProperty,
null, objApp_Late, Parameters);
}
catch (Exception theException)
{
String errorMessage;
errorMessage = "Error: ";
errorMessage = String.Concat(errorMessage, theException.Message);
errorMessage = String.Concat(errorMessage, " Line: ");
errorMessage = String.Concat(errorMessage, theException.Source);

MessageBox.Show(errorMessage, "Error");
}
}
}
}

Wednesday, 28 January 2009

Step by Step Accessing Oracle Store Procedures in .Net

In my last project, I was asked to develop a windows form application for our customers to forecast their sales and monitor the performance. I was using Oracle 10g release 2 as backend database and C# to develop the front-end. I am aware that Oracle has its own data provider for .net – ODP.net, which offers more features and probably gives better performance. This is something I would like to try in my next project, for this one I was using the standard MS data provider for Oracle. Here I would like to share some my own experience of developing oracle-based application on .Net, I am sure for one way or the other I wasn’t using the most efficient way but so far it works great for my customers, I appreciate any thought you may have on it.

For demonstration purposes, I am here using a sample table called Customers, I then created a sequence and two before insert/update triggers to populate Customer_Id, Create_Date and Last Date fields. I tend to use triggers to upsert the common attributes of the table, such as create_date or last_update column. Some people say using triggers maybe not as efficient as using SQL statement, this is probably true. But if the table doesn’t contain huge amount of data, it shouldn’t make much difference, I may post a performance comparison later. The gain of using triggers is also quite obvious, it simplifies the update/insert SQL and keeps your code clean in procedures.


create table customers
(
customer_id integer,
customer_name varchar2(30),
address varchar2(100),
create_date date,
last_update date,
constraint customer_pk primary key (customer_id)
)
/
create sequence seq_cust_id
start with 1
increment by 1
nomaxvalue
nocycle
cache 24
/
create trigger bi_customers
before insert on customers
for each row
begin
select seq_cust_id.nextval into :new.customer_id from dual;
:new.create_date := sysdate;
:new.last_update := sysdate;
end;
/
create trigger bu_customers
before update on customers
for each row
begin
:new.last_update := sysdate;
end;
/
insert into customers (customer_name, address) values ('abc', 'London');
insert into customers (customer_name, address) values ('bcd', 'Birmingham');
insert into customers (customer_name, address) values ('cde', 'Manchester');
insert into customers (customer_name, address) values ('def', 'Leeds');
insert into customers (customer_name, address) values ('efg', 'Cambridge');
insert into customers (customer_name, address) values ('fgh', 'Oxford');

The next step is to create package for CRUD operations. (Create, Retrieve, Update and Delete).


create or replace package crud_customers as

type t_cursor is ref cursor;

-- Create a new customer
procedure create_customer(p_cust_name varchar2, p_address varchar2);
-- Retrieve data
procedure retrieve_customers(p_cust_name in varchar2,
cur_customer out t_cursor);
-- Update operation
procedure update_customer(p_cust_id number,
p_cust_name varchar2,
p_address varchar2);
-- Delete operation
procedure delete_customer(p_cust_id in number);

end crud_customers;
/
create or replace package body crud_customers as

procedure create_customer(p_cust_name varchar2, p_address varchar2) as
begin
insert into customers
(customer_name, address)
values
(p_cust_name, p_address);
commit;
exception
when others then
rollback;
raise;
end create_customer;

procedure retrieve_customers(p_cust_name in varchar2,
cur_customer out t_cursor) as
begin
open cur_customer for
select customer_id, customer_name, address, create_date, last_update
from customers
where '-1' = nvl(p_cust_name, '-1')
or customer_name like '%' || p_cust_name || '%';
end retrieve_customers;

procedure update_customer(p_cust_id number,
p_cust_name varchar2,
p_address varchar2) as
begin
update customers
set customer_name = p_cust_name, address = p_address
where customers.customer_id = p_cust_id;

commit;
exception
when others then
rollback;
raise;
end update_customer;

procedure delete_customer(p_cust_id in number) as
begin
delete from customers where customer_id = p_cust_id;
commit;
end delete_customer;
end crud_customers;
/

Test the ref cursor output in the package:



Now we have completed all works in Oracle, it’s time to move to visual studio. Inside visual studio I created a project and named it as AccessOracleDemo.

Step 1: The first thing we need to do is to add OracleClient reference to references list. Note I have also added System.Configuration reference into the list, in this demo it used to store the database connection string.



Step 2: Set up the configuration file: app.config. Right click on the project name and select the properties. In setting tab, create a new connection string.



Once you saved the change, visual studio generates an app.config file for us. The content would be something like:






connectionString="Data Source=demo;Persist Security Info=True;User ID=scott;Password=xxxxxx;Unicode=True"
providerName="System.Data.OracleClient" />



There are various ways you can and you should encrypt your connection string here. But in this demo, I’ll leave it as it is.

Step 3: Create a class which read the connection string from app.config file and return it.

using System.Data.OracleClient;
using System.Configuration;

namespace AccessOracleDemo
{
///
/// Return the database connection string
///

class DBCONN
{
public static OracleConnection GetConnection()
{
// Get the current configuration file.
string connectionString =
ConfigurationManager.ConnectionStrings[1].ConnectionString.ToString();
return new OracleConnection(connectionString);
}
}
}

Step 4: Create a data access class. In this class, I created 4 command objects for CRUD operation.

using System;
using System.Data;
using System.Data.OracleClient;

namespace AccessOracleDemo
{
class DALCustomers
{
private OracleConnection conn;
private OracleCommand selectCommand = null;
private OracleCommand updateCommand = null;
private OracleCommand insertCommand = null;
private OracleCommand deleteCommand = null;
private OracleDataAdapter da;

public DataTable select_Customers(DataSet dsdata, string strCustomerName)
{
conn = DBCONN.GetConnection();
da = new OracleDataAdapter();
selectCommand = new OracleCommand();
selectCommand.CommandText = "crud_customers.retrieve_customers";
selectCommand.CommandType = CommandType.StoredProcedure;
selectCommand.Connection = conn;
selectCommand.Parameters.Add("p_cust_name", OracleType.VarChar, 30);
selectCommand.Parameters.Add("cur_customer", OracleType.Cursor).Direction = ParameterDirection.Output;
selectCommand.Parameters["p_cust_name"].Value = strCustomerName;

da = new OracleDataAdapter(selectCommand);

try
{
conn.Open();
if (!dsdata.Tables.Contains("customers"))
dsdata.Tables.Add("customers");
da.Fill(dsdata, "customers");
}
catch (OracleException oex)
{
throw new Exception(oex.Message);
}
finally
{
conn.Close();
}
return dsdata.Tables["customers"];
}

public int update_Customer(DataSet dsdata)
{
int rowAffected = 0;
da = new OracleDataAdapter();
conn = DBCONN.GetConnection();

updateCommand = new OracleCommand();
updateCommand.CommandText = "crud_customers.update_customer";
updateCommand.CommandType = CommandType.StoredProcedure;
updateCommand.Connection = conn;
updateCommand.Parameters.Add("p_cust_id", OracleType.Number, 4, "customer_id");
updateCommand.Parameters.Add("p_cust_name", OracleType.VarChar, 10, "customer_name");
updateCommand.Parameters.Add("p_address", OracleType.VarChar, 30, "address");

da.UpdateCommand = updateCommand;

try
{
conn.Open();
rowAffected = da.Update(dsdata.Tables["customers"].Select(null, null, DataViewRowState.ModifiedCurrent));
}
catch (Exception oex)
{
throw new Exception(oex.Message);
}
finally
{
conn.Close();
}
return rowAffected;
}

public int insert_Customer(DataSet dsdata)
{
int rowAffected = 0;
conn = DBCONN.GetConnection();
da = new OracleDataAdapter();

insertCommand = new OracleCommand();
insertCommand.CommandText = "crud_customers.create_customer";
insertCommand.CommandType = CommandType.StoredProcedure;
insertCommand.Connection = conn;

insertCommand.Parameters.Add("p_cust_name", OracleType.VarChar, 10, "customer_name");
insertCommand.Parameters.Add("p_address", OracleType.VarChar, 30, "address");

da.InsertCommand = insertCommand;

try
{
conn.Open();
rowAffected = da.Update(dsdata.Tables["customers"].Select(null, null, DataViewRowState.Added));
}
catch (Exception oex)
{
throw new Exception(oex.Message);
}
finally
{
conn.Close();
}
return rowAffected;
}

public void delete_Customer(int intCustomerID)
{
conn = DBCONN.GetConnection();
deleteCommand = new OracleCommand();
deleteCommand.CommandText = "crud_customers.delete_customer";
deleteCommand.CommandType = CommandType.StoredProcedure;
deleteCommand.Connection = conn;

deleteCommand.Parameters.Add("p_cust_id", OracleType.Number, 4);
deleteCommand.Parameters["p_cust_id"].Value = intCustomerID;

try
{
conn.Open();
deleteCommand.ExecuteNonQuery();
}
catch (OracleException oex)
{
throw new Exception(oex.Message);
}
finally
{
conn.Close();
}
}
}
}

Step 5: Drag one text box, three buttons and one DataGridView onto Windows form designer and give them a meaningful name.


using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;

namespace AccessOracleDemo
{
public partial class frmDemo : Form
{
public frmDemo()
{
InitializeComponent();
}

DALCustomers DBCustomers;
DataSet dsCustomer;

private void btnSearch_Click(object sender, EventArgs e)
{
PopulateDGV();
btnSave.Enabled = true;
btnDelete.Enabled = true;
}

private void btnSave_Click(object sender, EventArgs e)
{
List rowAffected = new List();
rowAffected = UpsertCustomers(dsCustomer);

if (rowAffected[0] == 0 && rowAffected[1] == 0)
MessageBox.Show("No change made!");
else
{
MessageBox.Show("You have successfully updated \n" + rowAffected[0].ToString() + " records; " +
"Inserted " + rowAffected[1].ToString() + " records;");
}
PopulateDGV();
}

private void btnDelete_Click(object sender, EventArgs e)
{
DeleteCustomer(dgvCustomers);
PopulateDGV();
}

private DataSet PopulateCustomers()
{
DBCustomers = new DALCustomers();
dsCustomer = new DataSet();
DBCustomers.select_Customers(dsCustomer, textSearch.Text.ToString());
return dsCustomer;
}

private void PopulateDGV()
{
dgvCustomers.DataSource = PopulateCustomers();
dgvCustomers.DataMember = "customers";
}

private List UpsertCustomers(DataSet ds)
{
List rowAffected = new List();
try
{
DBCustomers = new DALCustomers();
// Update table customers
if (ds.HasChanges())
rowAffected.Add(DBCustomers.update_Customer(ds));
else
rowAffected.Add(0);
// Insert table customers
if (ds.HasChanges())
rowAffected.Add(DBCustomers.insert_Customer(ds));
else
rowAffected.Add(0);
}
catch (Exception ex)
{
throw ex;
}
return rowAffected;
}

private void DeleteCustomer(DataGridView dgv)
{
try
{
DialogResult delResult;
delResult = MessageBox.Show("Do you really want to delete the item?", "Delete Confirmation",
MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (delResult == DialogResult.OK)
{
DBCustomers = new DALCustomers();
DBCustomers.delete_Customer(int.Parse(dgv.CurrentRow.Cells["customer_id"].Value.ToString()));
}
}
catch (Exception ex)
{
throw ex;
}
}
}
}

Step 6: We can now run and test the application, some screen shots as below:

Load data from Oracle:

Update and insert records into the table:

Delete a record:


Displaying data in tabular format is one of the common requirements in Windows-based applications. The DataGridView control, new in Windows Forms 2.0, is so versatile and powerful that beginners can easily be overwhelmed by the options. We can easily lock/unlock the rows/columns/cells, change the front/background color, re-format the columns, add some calculations…… without writing a single line of code. We can also change the column display type as dropdown or checkbox or datepicker or even cascading dropdown with only few lines of code. I’ll demonstrate some of them in my next posts. Feel free to let me know should you have any questions, problems or comments.