C
Carl Heller
Working in VS2003, .Net 1.1
I'm working on a project where I compare data between two databases. This
is a lengthy process, and very data intensive, so I decided to create a
class, and thread out the work.
The order of work is as follows:
1. Retrieve the data from primary data source
2. Update UI with retrieved data - this is accomplished by passing a
dataset as an event parameter
3. Compare retrieved data to a secondary data source, updating UI
occasionally.
I'm running into 1 problem, and one weirdness, and I'm hoping someone can
guide me where I went wrong.
Problem: After data is bound to the datagrid and the compare to the
secondary data source is going on, if I scroll through the datagrid I get an
exception "Object reference not set to an instance of an object, and the
datagrid disappears, replaced by a big red X. StackTrace:
System.NullReferenceException: Object reference not set to an instance of an
object.
at System.Data.DataColumnPropertyDescriptor.GetValue(Object component)
at
System.Windows.Forms.DataGridColumnStyle.GetColumnValueAtRow(CurrencyManager
source, Int32 rowNum)
at System.Windows.Forms.DataGridTextBoxColumn.Paint(Graphics g, Rectangle
bounds, CurrencyManager source, Int32 rowNum, Brush backBrush, Brush
foreBrush, Boolean alignToRight)
at
System.Windows.Forms.DataGridRelationshipRow.PaintCellContents(Graphics g,
Rectangle cellBounds, DataGridColumnStyle column, Brush backBr, Brush
foreBrush, Boolean alignToRight)
at System.Windows.Forms.DataGridRow.PaintData(Graphics g, Rectangle
bounds, Int32 firstVisibleColumn, Int32 columnCount, Boolean alignToRight)
at System.Windows.Forms.DataGridRelationshipRow.Paint(Graphics g,
Rectangle bounds, Rectangle trueRowBounds, Int32 firstVisibleColumn, Int32
numVisibleColumns, Boolean alignToRight)
at System.Windows.Forms.DataGrid.PaintRows(Graphics g, Rectangle&
boundingRect)
at System.Windows.Forms.DataGrid.PaintGrid(Graphics g, Rectangle
gridBounds)
at System.Windows.Forms.DataGrid.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e,
Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg,
IntPtr wparam, IntPtr lparam)
Weirdness:
While the compare to the secondary data source is going on, the thread's
dataset is being updated. But for some reason, the UI's dataset is being
updated as well. I thought that the UI would be working with a copy of the
thread's dataset when I do the BeginInvoke and create a new object, but it
obviously isn't. I have a feeling that my two issues are related, but I do
not have enough experience with threads to solve this.
I've provided a snip of the code so that you can understand how I'm making
the calls. If there is a better (more proper?) way of doing what I'm doing,
please educate me.
public class Verification //This is the class used by the worker thread
{
<snip>
private Verify()
{
dsVerification dsRetrievedData;
dsRetrievedData = RetrieveData();
DataUpdatedEvent (this, new StatusEventArgs(dsRetrievedData);
CompareToSecondary(dsRetrievedData);
}
<snip>
public delegate void DataUpdated(object sender, StatusEventArgs e);
public event DataUpdated DataUpdatedEvent;
} //End of Verification Class
private DataGrid dataGridVerification;
private Verifiy ioVerification;
private Thread ioThread;
private delegate void DataUpdatedDelegate(dsVerification adsRetrievedData);
private void DataUpdated (dsVerification adsRetrievedData)
{
dataGridVerification.DataSource = adsData.VerificationData;
}
private void ioVerification_DataUpdatedEvent(object sender, StatusEventArgs
e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new DataUpdatedDelegate(DataUpdated), new object[]
{e.Data});
return;
}
DataUpdated(e.Data);
}
I'm working on a project where I compare data between two databases. This
is a lengthy process, and very data intensive, so I decided to create a
class, and thread out the work.
The order of work is as follows:
1. Retrieve the data from primary data source
2. Update UI with retrieved data - this is accomplished by passing a
dataset as an event parameter
3. Compare retrieved data to a secondary data source, updating UI
occasionally.
I'm running into 1 problem, and one weirdness, and I'm hoping someone can
guide me where I went wrong.
Problem: After data is bound to the datagrid and the compare to the
secondary data source is going on, if I scroll through the datagrid I get an
exception "Object reference not set to an instance of an object, and the
datagrid disappears, replaced by a big red X. StackTrace:
System.NullReferenceException: Object reference not set to an instance of an
object.
at System.Data.DataColumnPropertyDescriptor.GetValue(Object component)
at
System.Windows.Forms.DataGridColumnStyle.GetColumnValueAtRow(CurrencyManager
source, Int32 rowNum)
at System.Windows.Forms.DataGridTextBoxColumn.Paint(Graphics g, Rectangle
bounds, CurrencyManager source, Int32 rowNum, Brush backBrush, Brush
foreBrush, Boolean alignToRight)
at
System.Windows.Forms.DataGridRelationshipRow.PaintCellContents(Graphics g,
Rectangle cellBounds, DataGridColumnStyle column, Brush backBr, Brush
foreBrush, Boolean alignToRight)
at System.Windows.Forms.DataGridRow.PaintData(Graphics g, Rectangle
bounds, Int32 firstVisibleColumn, Int32 columnCount, Boolean alignToRight)
at System.Windows.Forms.DataGridRelationshipRow.Paint(Graphics g,
Rectangle bounds, Rectangle trueRowBounds, Int32 firstVisibleColumn, Int32
numVisibleColumns, Boolean alignToRight)
at System.Windows.Forms.DataGrid.PaintRows(Graphics g, Rectangle&
boundingRect)
at System.Windows.Forms.DataGrid.PaintGrid(Graphics g, Rectangle
gridBounds)
at System.Windows.Forms.DataGrid.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e,
Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg,
IntPtr wparam, IntPtr lparam)
Weirdness:
While the compare to the secondary data source is going on, the thread's
dataset is being updated. But for some reason, the UI's dataset is being
updated as well. I thought that the UI would be working with a copy of the
thread's dataset when I do the BeginInvoke and create a new object, but it
obviously isn't. I have a feeling that my two issues are related, but I do
not have enough experience with threads to solve this.
I've provided a snip of the code so that you can understand how I'm making
the calls. If there is a better (more proper?) way of doing what I'm doing,
please educate me.
public class Verification //This is the class used by the worker thread
{
<snip>
private Verify()
{
dsVerification dsRetrievedData;
dsRetrievedData = RetrieveData();
DataUpdatedEvent (this, new StatusEventArgs(dsRetrievedData);
CompareToSecondary(dsRetrievedData);
}
<snip>
public delegate void DataUpdated(object sender, StatusEventArgs e);
public event DataUpdated DataUpdatedEvent;
} //End of Verification Class
private DataGrid dataGridVerification;
private Verifiy ioVerification;
private Thread ioThread;
private delegate void DataUpdatedDelegate(dsVerification adsRetrievedData);
private void DataUpdated (dsVerification adsRetrievedData)
{
dataGridVerification.DataSource = adsData.VerificationData;
}
private void ioVerification_DataUpdatedEvent(object sender, StatusEventArgs
e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new DataUpdatedDelegate(DataUpdated), new object[]
{e.Data});
return;
}
DataUpdated(e.Data);
}