How to correctly handle exceptions in other threads

S

Steve B.

Hi,

I'm building a device application that works on two threads (using VS 2005
and CF 2.0).

I'm using threads because one of my operations is quite long (up to 30
minutes or more), and I want to display the user a progress bar and messages
in a listbox.
This operation is a Sql Mobile Merge replication, but I suppose handling
exceptions in other theads is quite standard.

I've a class that handle the replication, and below is a part of the code I
use.
I'd like to know how to correctly handle any exception in the second thread
?

The "DoSynchronize" method must exit only when the replication has finished.
I use BeginSynchronize to enable firing events. If an exception occurs while
replicating, I want the exception to be thrown to the DoSynchronize calling
method.

What have I to do ?

Below is the partial code of my replication manager [1] and the form that
should display the progression (in a list box)[2]

Thanks,
Steve

[1]
public class SqlCeReplicationManager
{
private static System.Threading.AutoResetEvent _isSync = new
System.Threading.AutoResetEvent(false);

#region Synchronization progression monitoring

/// <summary>
/// Notify when a table is downloaded
/// </summary>
public event EventHandler<TableTransferedEventArgs> TableDownloaded;
/// <summary>
/// Notify when a table is uploaded
/// </summary>
public event EventHandler<TableTransferedEventArgs> TableUploaded;
/// <summary>
/// Notify the progression of the synchronization
/// </summary>
public event EventHandler<SynchronizationStepEventArgs> SynchronizationStep;
/// <summary>
/// Notify when the synchronization complete
/// </summary>
public event EventHandler<SynchronizationCompletedEventArgs>
SynchronizationCompleted;

#endregion

private void DoSynchronize(SqlCeReplication repl)
{
//repl.Synchronize();
repl.BeginSynchronize(
new AsyncCallback(this.SyncCompletedCallBack),
new OnStartTableUpload(this.OnStartTableUploadCallBack),
new OnStartTableDownload(this.OnStartTableDownloadCallBack),
new OnSynchronization(this.OnSynchronizationCallBack),
repl
);
_isSync.WaitOne();
}
private void SyncCompletedCallBack(IAsyncResult ar)
{
((SqlCeReplication)ar.AsyncState).EndSynchronize(ar);
if (this.SynchronizationCompleted != null)
{
this.SynchronizationCompleted(
this,
new SynchronizationCompletedEventArgs(new
ChangesStats((SqlCeReplication)ar.AsyncState))
);
}
_isSync.Set();
}
private void OnStartTableUploadCallBack(
IAsyncResult ar,
string tableName
)
{
if (this.TableUploaded != null)
{
this.TableUploaded(
this,
new TableTransferedEventArgs(tableName)
);
}
}
private void OnStartTableDownloadCallBack(
IAsyncResult ar,
string tableName
)
{
if (this.TableDownloaded != null)
{
this.TableDownloaded(
this,
new TableTransferedEventArgs(tableName)
);
}
}
private void OnSynchronizationCallBack(
IAsyncResult ar,
int percentComplete
)
{
if (this.SynchronizationStep != null)
{
this.SynchronizationStep(
this,
new SynchronizationStepEventArgs(percentComplete)
);
}
}
private void CancelSynchronize()
{
GetReplicationObject().CancelSynchronize();
_isSync.Set();
}

}

public partial class frmSqlRepl : Form
{
public frmSqlRepl()
{
InitializeComponent();

SqlCeReplicationManager1.TableUploaded +=
new EventHandler<TableTransferedEventArgs>(
SqlCeReplicationManager1_TableUploaded
);
SqlCeReplicationManager1.TableDownloaded +=
new EventHandler<TableTransferedEventArgs>(
SqlCeReplicationManager1_TableDownloaded
);
SqlCeReplicationManager1.SynchronizationStep +=
new EventHandler<SynchronizationStepEventArgs>(
SqlCeReplicationManager1_SynchronizationStep
);
SqlCeReplicationManager1.SynchronizationCompleted +=
new EventHandler<SynchronizationCompletedEventArgs>(
SqlCeReplicationManager1_SynchronizationComplete
);

}

delegate void AddDelegate(string msg);

void Add(string msg) // Insert a msg at the top of the listbox
{
lstOutput.Items.Insert(0, msg);
}
void SqlCeReplicationManager1_SynchronizationComplete(
object sender,
SynchronizationCompletedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"SynchronizarionComplete : " + e.Stats.ToString()
);
}

void SqlCeReplicationManager1_SynchronizationStep(
object sender,
SynchronizationStepEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"SynchronizarionStep : " + e.PercentComplete.ToString() +
"%"
);
}

void SqlCeReplicationManager1_TableDownloaded(
object sender,
TableTransferedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"TableDownloaded : " + e.TableName
);
}

void SqlCeReplicationManager1_TableUploaded(
object sender,
TableTransferedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"TableUploaded : " + e.TableName
);
}

}
 
C

Chris Tacke, MVP

Since the caller is asynchronous, an exception in the thread can't be
detected to be at any specific point. The thread should raise an internal
event that the primary thread is listening to to notify it that the
exception has occurred.

-Chris


Steve B. said:
Hi,

I'm building a device application that works on two threads (using VS 2005
and CF 2.0).

I'm using threads because one of my operations is quite long (up to 30
minutes or more), and I want to display the user a progress bar and
messages in a listbox.
This operation is a Sql Mobile Merge replication, but I suppose handling
exceptions in other theads is quite standard.

I've a class that handle the replication, and below is a part of the code
I use.
I'd like to know how to correctly handle any exception in the second
thread ?

The "DoSynchronize" method must exit only when the replication has
finished. I use BeginSynchronize to enable firing events. If an exception
occurs while replicating, I want the exception to be thrown to the
DoSynchronize calling method.

What have I to do ?

Below is the partial code of my replication manager [1] and the form that
should display the progression (in a list box)[2]

Thanks,
Steve

[1]
public class SqlCeReplicationManager
{
private static System.Threading.AutoResetEvent _isSync = new
System.Threading.AutoResetEvent(false);

#region Synchronization progression monitoring

/// <summary>
/// Notify when a table is downloaded
/// </summary>
public event EventHandler<TableTransferedEventArgs> TableDownloaded;
/// <summary>
/// Notify when a table is uploaded
/// </summary>
public event EventHandler<TableTransferedEventArgs> TableUploaded;
/// <summary>
/// Notify the progression of the synchronization
/// </summary>
public event EventHandler<SynchronizationStepEventArgs>
SynchronizationStep;
/// <summary>
/// Notify when the synchronization complete
/// </summary>
public event EventHandler<SynchronizationCompletedEventArgs>
SynchronizationCompleted;

#endregion

private void DoSynchronize(SqlCeReplication repl)
{
//repl.Synchronize();
repl.BeginSynchronize(
new AsyncCallback(this.SyncCompletedCallBack),
new OnStartTableUpload(this.OnStartTableUploadCallBack),
new OnStartTableDownload(this.OnStartTableDownloadCallBack),
new OnSynchronization(this.OnSynchronizationCallBack),
repl
);
_isSync.WaitOne();
}
private void SyncCompletedCallBack(IAsyncResult ar)
{
((SqlCeReplication)ar.AsyncState).EndSynchronize(ar);
if (this.SynchronizationCompleted != null)
{
this.SynchronizationCompleted(
this,
new SynchronizationCompletedEventArgs(new
ChangesStats((SqlCeReplication)ar.AsyncState))
);
}
_isSync.Set();
}
private void OnStartTableUploadCallBack(
IAsyncResult ar,
string tableName
)
{
if (this.TableUploaded != null)
{
this.TableUploaded(
this,
new TableTransferedEventArgs(tableName)
);
}
}
private void OnStartTableDownloadCallBack(
IAsyncResult ar,
string tableName
)
{
if (this.TableDownloaded != null)
{
this.TableDownloaded(
this,
new TableTransferedEventArgs(tableName)
);
}
}
private void OnSynchronizationCallBack(
IAsyncResult ar,
int percentComplete
)
{
if (this.SynchronizationStep != null)
{
this.SynchronizationStep(
this,
new SynchronizationStepEventArgs(percentComplete)
);
}
}
private void CancelSynchronize()
{
GetReplicationObject().CancelSynchronize();
_isSync.Set();
}

}

public partial class frmSqlRepl : Form
{
public frmSqlRepl()
{
InitializeComponent();

SqlCeReplicationManager1.TableUploaded +=
new EventHandler<TableTransferedEventArgs>(
SqlCeReplicationManager1_TableUploaded
);
SqlCeReplicationManager1.TableDownloaded +=
new EventHandler<TableTransferedEventArgs>(
SqlCeReplicationManager1_TableDownloaded
);
SqlCeReplicationManager1.SynchronizationStep +=
new EventHandler<SynchronizationStepEventArgs>(
SqlCeReplicationManager1_SynchronizationStep
);
SqlCeReplicationManager1.SynchronizationCompleted +=
new EventHandler<SynchronizationCompletedEventArgs>(
SqlCeReplicationManager1_SynchronizationComplete
);

}

delegate void AddDelegate(string msg);

void Add(string msg) // Insert a msg at the top of the listbox
{
lstOutput.Items.Insert(0, msg);
}
void SqlCeReplicationManager1_SynchronizationComplete(
object sender,
SynchronizationCompletedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"SynchronizarionComplete : " + e.Stats.ToString()
);
}

void SqlCeReplicationManager1_SynchronizationStep(
object sender,
SynchronizationStepEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"SynchronizarionStep : " + e.PercentComplete.ToString() +
"%"
);
}

void SqlCeReplicationManager1_TableDownloaded(
object sender,
TableTransferedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"TableDownloaded : " + e.TableName
);
}

void SqlCeReplicationManager1_TableUploaded(
object sender,
TableTransferedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"TableUploaded : " + e.TableName
);
}

}
 
S

Steve B.

I've made some search and found I can use the "BeginXXX" and "EndXXX" to
reach my goal. Any exception thrown in the second thread should be raised on
the EndXXX call, doesn't it ?

But with this approach, when I call listbox1.Invoke(...) to update the value
of a litsbox in its thread, the code hangs on the line listbox1.Invoke(...).

My updated code is this one :

try
{
if (!File.Exists(GlobalConnection.Default.LocalDataBaseFile))
this.InitLocalDatabase(false);
//repl.Synchronize();
IAsyncResult ar = repl.BeginSynchronize(
new AsyncCallback(this.SyncCompletedCallBack),
new OnStartTableUpload(this.OnStartTableUploadCallBack),
new OnStartTableDownload(this.OnStartTableDownloadCallBack),
new OnSynchronization(this.OnSynchronizationCallBack),
repl
);
ar.AsyncWaitHandle.WaitOne();
repl.EndSynchronize(ar);
}
catch (SqlCeException exc)
{
.... Custom exception handling ...
}

The 4 delegated methods throw an event in my replication manager that is
handled by the application

void Default_SynchronizationStep(object sender, SynchronizationStepEventArgs
e)

{

this.Invoke(

new AddDelegate(Add),

"SynchronizarionStep : " + e.PercentComplete.ToString() + "%"

); // this line hangs the application


}

If I replace the Invoke Method by BeginInvoke method, it does not hangs, but
the listbox update its value only after the EndSynchronize has been called.

Thanks,
Steve

Chris Tacke said:
Since the caller is asynchronous, an exception in the thread can't be
detected to be at any specific point. The thread should raise an internal
event that the primary thread is listening to to notify it that the
exception has occurred.

-Chris


Steve B. said:
Hi,

I'm building a device application that works on two threads (using VS
2005 and CF 2.0).

I'm using threads because one of my operations is quite long (up to 30
minutes or more), and I want to display the user a progress bar and
messages in a listbox.
This operation is a Sql Mobile Merge replication, but I suppose handling
exceptions in other theads is quite standard.

I've a class that handle the replication, and below is a part of the code
I use.
I'd like to know how to correctly handle any exception in the second
thread ?

The "DoSynchronize" method must exit only when the replication has
finished. I use BeginSynchronize to enable firing events. If an exception
occurs while replicating, I want the exception to be thrown to the
DoSynchronize calling method.

What have I to do ?

Below is the partial code of my replication manager [1] and the form that
should display the progression (in a list box)[2]

Thanks,
Steve

[1]
public class SqlCeReplicationManager
{
private static System.Threading.AutoResetEvent _isSync = new
System.Threading.AutoResetEvent(false);

#region Synchronization progression monitoring

/// <summary>
/// Notify when a table is downloaded
/// </summary>
public event EventHandler<TableTransferedEventArgs> TableDownloaded;
/// <summary>
/// Notify when a table is uploaded
/// </summary>
public event EventHandler<TableTransferedEventArgs> TableUploaded;
/// <summary>
/// Notify the progression of the synchronization
/// </summary>
public event EventHandler<SynchronizationStepEventArgs>
SynchronizationStep;
/// <summary>
/// Notify when the synchronization complete
/// </summary>
public event EventHandler<SynchronizationCompletedEventArgs>
SynchronizationCompleted;

#endregion

private void DoSynchronize(SqlCeReplication repl)
{
//repl.Synchronize();
repl.BeginSynchronize(
new AsyncCallback(this.SyncCompletedCallBack),
new OnStartTableUpload(this.OnStartTableUploadCallBack),
new OnStartTableDownload(this.OnStartTableDownloadCallBack),
new OnSynchronization(this.OnSynchronizationCallBack),
repl
);
_isSync.WaitOne();
}
private void SyncCompletedCallBack(IAsyncResult ar)
{
((SqlCeReplication)ar.AsyncState).EndSynchronize(ar);
if (this.SynchronizationCompleted != null)
{
this.SynchronizationCompleted(
this,
new SynchronizationCompletedEventArgs(new
ChangesStats((SqlCeReplication)ar.AsyncState))
);
}
_isSync.Set();
}
private void OnStartTableUploadCallBack(
IAsyncResult ar,
string tableName
)
{
if (this.TableUploaded != null)
{
this.TableUploaded(
this,
new TableTransferedEventArgs(tableName)
);
}
}
private void OnStartTableDownloadCallBack(
IAsyncResult ar,
string tableName
)
{
if (this.TableDownloaded != null)
{
this.TableDownloaded(
this,
new TableTransferedEventArgs(tableName)
);
}
}
private void OnSynchronizationCallBack(
IAsyncResult ar,
int percentComplete
)
{
if (this.SynchronizationStep != null)
{
this.SynchronizationStep(
this,
new SynchronizationStepEventArgs(percentComplete)
);
}
}
private void CancelSynchronize()
{
GetReplicationObject().CancelSynchronize();
_isSync.Set();
}

}

public partial class frmSqlRepl : Form
{
public frmSqlRepl()
{
InitializeComponent();

SqlCeReplicationManager1.TableUploaded +=
new EventHandler<TableTransferedEventArgs>(
SqlCeReplicationManager1_TableUploaded
);
SqlCeReplicationManager1.TableDownloaded +=
new EventHandler<TableTransferedEventArgs>(
SqlCeReplicationManager1_TableDownloaded
);
SqlCeReplicationManager1.SynchronizationStep +=
new EventHandler<SynchronizationStepEventArgs>(
SqlCeReplicationManager1_SynchronizationStep
);
SqlCeReplicationManager1.SynchronizationCompleted +=
new EventHandler<SynchronizationCompletedEventArgs>(
SqlCeReplicationManager1_SynchronizationComplete
);

}

delegate void AddDelegate(string msg);

void Add(string msg) // Insert a msg at the top of the listbox
{
lstOutput.Items.Insert(0, msg);
}
void SqlCeReplicationManager1_SynchronizationComplete(
object sender,
SynchronizationCompletedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"SynchronizarionComplete : " + e.Stats.ToString()
);
}

void SqlCeReplicationManager1_SynchronizationStep(
object sender,
SynchronizationStepEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"SynchronizarionStep : " + e.PercentComplete.ToString() +
"%"
);
}

void SqlCeReplicationManager1_TableDownloaded(
object sender,
TableTransferedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"TableDownloaded : " + e.TableName
);
}

void SqlCeReplicationManager1_TableUploaded(
object sender,
TableTransferedEventArgs e
)
{
lstOutput.Invoke(
new AddDelegate(Add),
"TableUploaded : " + e.TableName
);
}

}
 
W

Willy Denoyette [MVP]

That means that repl.EndSynchronize(ar); is called from your UI thread, so
you are blocking your UI thread. Worse, you call Invoke(which is blocking
until the message has ben handled by the UI thread, but this one is
blocked - that means deadlock.
You should never call any wait function (ar.AsyncWaitHandle.WaitOne();) on
the UI thread, so move this whole code to a separate thread.

Willy.

| I've made some search and found I can use the "BeginXXX" and "EndXXX" to
| reach my goal. Any exception thrown in the second thread should be raised
on
| the EndXXX call, doesn't it ?
|
| But with this approach, when I call listbox1.Invoke(...) to update the
value
| of a litsbox in its thread, the code hangs on the line
listbox1.Invoke(...).
|
| My updated code is this one :
|
| try
| {
| if (!File.Exists(GlobalConnection.Default.LocalDataBaseFile))
| this.InitLocalDatabase(false);
| //repl.Synchronize();
| IAsyncResult ar = repl.BeginSynchronize(
| new AsyncCallback(this.SyncCompletedCallBack),
| new OnStartTableUpload(this.OnStartTableUploadCallBack),
| new OnStartTableDownload(this.OnStartTableDownloadCallBack),
| new OnSynchronization(this.OnSynchronizationCallBack),
| repl
| );
| ar.AsyncWaitHandle.WaitOne();
| repl.EndSynchronize(ar);
| }
| catch (SqlCeException exc)
| {
| ... Custom exception handling ...
| }
|
| The 4 delegated methods throw an event in my replication manager that is
| handled by the application
|
| void Default_SynchronizationStep(object sender,
SynchronizationStepEventArgs
| e)
|
| {
|
| this.Invoke(
|
| new AddDelegate(Add),
|
| "SynchronizarionStep : " + e.PercentComplete.ToString() + "%"
|
| ); // this line hangs the application
|
|
| }
|
| If I replace the Invoke Method by BeginInvoke method, it does not hangs,
but
| the listbox update its value only after the EndSynchronize has been
called.
|
| Thanks,
| Steve
|
| "Chris Tacke, MVP" <[email protected]> a écrit dans le message
| de news: (e-mail address removed)...
| > Since the caller is asynchronous, an exception in the thread can't be
| > detected to be at any specific point. The thread should raise an
internal
| > event that the primary thread is listening to to notify it that the
| > exception has occurred.
| >
| > -Chris
| >
| >
| > | >> Hi,
| >>
| >> I'm building a device application that works on two threads (using VS
| >> 2005 and CF 2.0).
| >>
| >> I'm using threads because one of my operations is quite long (up to 30
| >> minutes or more), and I want to display the user a progress bar and
| >> messages in a listbox.
| >> This operation is a Sql Mobile Merge replication, but I suppose
handling
| >> exceptions in other theads is quite standard.
| >>
| >> I've a class that handle the replication, and below is a part of the
code
| >> I use.
| >> I'd like to know how to correctly handle any exception in the second
| >> thread ?
| >>
| >> The "DoSynchronize" method must exit only when the replication has
| >> finished. I use BeginSynchronize to enable firing events. If an
exception
| >> occurs while replicating, I want the exception to be thrown to the
| >> DoSynchronize calling method.
| >>
| >> What have I to do ?
| >>
| >> Below is the partial code of my replication manager [1] and the form
that
| >> should display the progression (in a list box)[2]
| >>
| >> Thanks,
| >> Steve
| >>
| >> [1]
| >> public class SqlCeReplicationManager
| >> {
| >> private static System.Threading.AutoResetEvent _isSync = new
| >> System.Threading.AutoResetEvent(false);
| >>
| >> #region Synchronization progression monitoring
| >>
| >> /// <summary>
| >> /// Notify when a table is downloaded
| >> /// </summary>
| >> public event EventHandler<TableTransferedEventArgs> TableDownloaded;
| >> /// <summary>
| >> /// Notify when a table is uploaded
| >> /// </summary>
| >> public event EventHandler<TableTransferedEventArgs> TableUploaded;
| >> /// <summary>
| >> /// Notify the progression of the synchronization
| >> /// </summary>
| >> public event EventHandler<SynchronizationStepEventArgs>
| >> SynchronizationStep;
| >> /// <summary>
| >> /// Notify when the synchronization complete
| >> /// </summary>
| >> public event EventHandler<SynchronizationCompletedEventArgs>
| >> SynchronizationCompleted;
| >>
| >> #endregion
| >>
| >> private void DoSynchronize(SqlCeReplication repl)
| >> {
| >> //repl.Synchronize();
| >> repl.BeginSynchronize(
| >> new AsyncCallback(this.SyncCompletedCallBack),
| >> new OnStartTableUpload(this.OnStartTableUploadCallBack),
| >> new OnStartTableDownload(this.OnStartTableDownloadCallBack),
| >> new OnSynchronization(this.OnSynchronizationCallBack),
| >> repl
| >> );
| >> _isSync.WaitOne();
| >> }
| >> private void SyncCompletedCallBack(IAsyncResult ar)
| >> {
| >> ((SqlCeReplication)ar.AsyncState).EndSynchronize(ar);
| >> if (this.SynchronizationCompleted != null)
| >> {
| >> this.SynchronizationCompleted(
| >> this,
| >> new SynchronizationCompletedEventArgs(new
| >> ChangesStats((SqlCeReplication)ar.AsyncState))
| >> );
| >> }
| >> _isSync.Set();
| >> }
| >> private void OnStartTableUploadCallBack(
| >> IAsyncResult ar,
| >> string tableName
| >> )
| >> {
| >> if (this.TableUploaded != null)
| >> {
| >> this.TableUploaded(
| >> this,
| >> new TableTransferedEventArgs(tableName)
| >> );
| >> }
| >> }
| >> private void OnStartTableDownloadCallBack(
| >> IAsyncResult ar,
| >> string tableName
| >> )
| >> {
| >> if (this.TableDownloaded != null)
| >> {
| >> this.TableDownloaded(
| >> this,
| >> new TableTransferedEventArgs(tableName)
| >> );
| >> }
| >> }
| >> private void OnSynchronizationCallBack(
| >> IAsyncResult ar,
| >> int percentComplete
| >> )
| >> {
| >> if (this.SynchronizationStep != null)
| >> {
| >> this.SynchronizationStep(
| >> this,
| >> new SynchronizationStepEventArgs(percentComplete)
| >> );
| >> }
| >> }
| >> private void CancelSynchronize()
| >> {
| >> GetReplicationObject().CancelSynchronize();
| >> _isSync.Set();
| >> }
| >>
| >> }
| >>
| >> public partial class frmSqlRepl : Form
| >> {
| >> public frmSqlRepl()
| >> {
| >> InitializeComponent();
| >>
| >> SqlCeReplicationManager1.TableUploaded +=
| >> new EventHandler<TableTransferedEventArgs>(
| >> SqlCeReplicationManager1_TableUploaded
| >> );
| >> SqlCeReplicationManager1.TableDownloaded +=
| >> new EventHandler<TableTransferedEventArgs>(
| >> SqlCeReplicationManager1_TableDownloaded
| >> );
| >> SqlCeReplicationManager1.SynchronizationStep +=
| >> new EventHandler<SynchronizationStepEventArgs>(
| >> SqlCeReplicationManager1_SynchronizationStep
| >> );
| >> SqlCeReplicationManager1.SynchronizationCompleted +=
| >> new EventHandler<SynchronizationCompletedEventArgs>(
| >> SqlCeReplicationManager1_SynchronizationComplete
| >> );
| >>
| >> }
| >>
| >> delegate void AddDelegate(string msg);
| >>
| >> void Add(string msg) // Insert a msg at the top of the listbox
| >> {
| >> lstOutput.Items.Insert(0, msg);
| >> }
| >> void SqlCeReplicationManager1_SynchronizationComplete(
| >> object sender,
| >> SynchronizationCompletedEventArgs e
| >> )
| >> {
| >> lstOutput.Invoke(
| >> new AddDelegate(Add),
| >> "SynchronizarionComplete : " + e.Stats.ToString()
| >> );
| >> }
| >>
| >> void SqlCeReplicationManager1_SynchronizationStep(
| >> object sender,
| >> SynchronizationStepEventArgs e
| >> )
| >> {
| >> lstOutput.Invoke(
| >> new AddDelegate(Add),
| >> "SynchronizarionStep : " + e.PercentComplete.ToString()
+
| >> "%"
| >> );
| >> }
| >>
| >> void SqlCeReplicationManager1_TableDownloaded(
| >> object sender,
| >> TableTransferedEventArgs e
| >> )
| >> {
| >> lstOutput.Invoke(
| >> new AddDelegate(Add),
| >> "TableDownloaded : " + e.TableName
| >> );
| >> }
| >>
| >> void SqlCeReplicationManager1_TableUploaded(
| >> object sender,
| >> TableTransferedEventArgs e
| >> )
| >> {
| >> lstOutput.Invoke(
| >> new AddDelegate(Add),
| >> "TableUploaded : " + e.TableName
| >> );
| >> }
| >>
| >> }
| >>
| >>
| >
| >
|
|
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top