Throw event in the main thread from worker thread C# CF
I have, what probably is, a simple problem. I'm using interop to call an asynchronous function in CompactFramework. After I get result of the execution, I would like to raise an event, that will be caught by the form, and based on the results, I would render some data on the screen. The problem, however, is that when interop functio开发者_运维技巧n returns a result, it returns it on a worker thread, and if I raise an event, it will stay on the worker thread and I can't render any data in the form, unless I use Invoke.
Can somebody suggest a way to merge worker thread onto the main thread? And raise an event from the main thread? I found a few examples that loop through the delegates subscribed to the event and use BeginInvoke to raise an event in main thread, however, they all use ISynchronizeInvoke, which is not available in Compact Framework.
My code is below:
public delegate void CellTowerFoundEventHandler(CellTower towerInfo);
public class CellTowerProvider
{
public delegate void RILRESULTCALLBACK(uint dwCode, IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam);
public delegate void RILNOTIFYCALLBACK(uint dwCode, IntPtr lpData, uint cbData, uint dwParam);
private RILCELLTOWERINFO towerDetails;
private CellTower cellTowerInfo;
private IntPtr radioInterfaceLayerHandle;
public CellTowerProvider()
{
radioInterfaceLayerHandle = IntPtr.Zero;
IntPtr radioResponseHandle = IntPtr.Zero;
// Initialize the radio layer with a result callback parameter.
radioResponseHandle = RIL_Initialize(1, new RILRESULTCALLBACK(CellDataCallback), null, 0, 0, out radioInterfaceLayerHandle);
// The initialize API call will always return 0 if initialization is successful.
if (radioResponseHandle != IntPtr.Zero)
{
return;
}
// Query for the current tower data.
radioResponseHandle = RIL_GetCellTowerInfo(radioInterfaceLayerHandle);
}
public void CellDataCallback(uint dwCode, IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam)
{
// Refresh the current tower details
towerDetails = new RILCELLTOWERINFO();
// Copy result returned from RIL into structure
Marshal.PtrToStructure(lpData, towerDetails);
cellTowerInfo = new CellTower()
{
TowerId = Convert.ToInt32(towerDetails.dwCellID),
LocationAreaCode = Convert.ToInt32(towerDetails.dwLocationAreaCode),
MobileCountryCode = Convert.ToInt32(towerDetails.dwMobileCountryCode),
MobileNetworkCode = Convert.ToInt32(towerDetails.dwMobileNetworkCode),
};
if (CellTowerFound != null)
CellTowerFound(cellTowerInfo);
// Release the RIL handle
RIL_Deinitialize(radioInterfaceLayerHandle);
}
}
Why not create a Control in the ctor of your library object? If you assume that the library instance is created in the UI thread, you can then call Control.Invoke on that control internal to your library, and the event call will be on the UI thread in the consumer.
Of course this isn't infallible. The consumer might create the instance in a worker, but it at least provides some level of what you're after and if they use a worker thread, they'd actually expect events to need an Invoke call anyway.
Well, Invoke is the (proper) way to 'merge' (sync) a Thread with with the main thread. The easiest ways is to use a Control (eg MainForm) and call ctl.Invoke(myDelegate)
.
And second, we raise events and throw exceptions. Using the right words avoids confusion.
This depends on what toolkit you're using to display data in your "main thread". If you're using Windows Forms, you should be able to use Control.Invoke or Control.BeginInvoke to marshal the event back onto the UI thread. This is supported in the Compact Framework.
Most samples use ISynchronizeInvoke instead of a control - but the code should be identical. You'll need a reference to a UI element in your code, though, to use with the call to BeginInvoke when you raise your event.
精彩评论