TaskCompletionSource never completes - c#

I have a websocket connection and I want to make get methods for it. I used this example.
This is a part of the data model:
public class Message
{
public string MessageType { get; set; }
}
public class SensorData : Message
{
public float Temperature { get; set; }
public float Humidity { get; set; }
public float Pressure { get; set; }
}
This is the websocket class:
public WebSocketConnection(string url)
{
socket = new WebSocket(url);
}
private WebSocket socket;
public int Timeout = 10000;
public void Connect()
{
socket.Connect();
socket.OnMessage += Socket_OnMessage;
}
public void Disconnect()
{
socket.Close();
socket.OnMessage -= Socket_OnMessage;
}
public event EventHandler<OnSensorDataEventArgs> SensorDataReveived;
private void Socket_OnMessage(object sender, MessageEventArgs e)
{
var msg = JsonConvert.DeserializeObject<Message>(e.Data);
switch (msg.MessageType)
{
case "other message types":
{
...
}
case "SensorData":
{
SensorDataReveived?.Invoke(this, new OnSensorDataEventArgs(JsonConvert.DeserializeObject<SensorData>(e.Data)));
break;
}
}
}
public Task<SensorData> GetSensorData()
{
var msg = JsonConvert.SerializeObject(new Message() { MessageType = "RequestSensorData" });
var tcs = new TaskCompletionSource<SensorData>();
SensorDataReveived += (sender, e) => {
tcs.SetResult(e.SensorData);
};
socket.Send(msg);
return tcs.Task;
}
The problem is the GetSensorData method. When socket.Send(msg) is called, the websocket server answers and the event is triggered, but after the SetResult call there happens nothing. I already tried TaskCreationOptions.RunContinuationsAsynchronously and wrapping SetResult in a Task.Run but that didn't help.
private async void BtnShowSensorData_Clicked(object sender, EventArgs e)
{
var sensorData = await connection.GetSensorData(); //Connection is an instance of WebSocketConnection
labelTemperature.Text = " Temperature: " + sensorData.Temperature.ToString();
labelHumidity.Text = " Humidity: " + sensorData.Humidity.ToString();
labelPressure.Text = " Pressure: " + sensorData.Pressure.ToString();
}

Related

Tcp wcf service hosted on winforms or wpf hangs

I am getting an error in Tcp Wcf Service hosted on winforms or WPF.
The service either hangs or throws "Thread Exited" error.
The same code works fine in a console application.
Thanks.
Server:
namespace WCFService
{
//interface declarations just like the client but the callback
//decleration is a little different
[ServiceContract]
interface IMessageCallback
{
[OperationContract(IsOneWay = true)]
void OnMessageAdded(string message, DateTime timestamp);
}
//This is a little different than the client
// in that we need to state the SessionMode as required or it will default to "notAllowed"
[ServiceContract(CallbackContract = typeof(IMessageCallback), SessionMode = SessionMode.Required)]
public interface IMessage
{
[OperationContract]
void AddMessage(string message);
[OperationContract]
bool Subscribe();
[OperationContract]
bool Unsubscribe();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class RCRServer : IMessage
{
private static List<IMessageCallback> subscribers = new List<IMessageCallback>();
public ServiceHost host = null;
public void Connect()
{
//I'm doing this next part progromatically instead of in app.cfg
// because I think it makes it easier to understand (and xml is stupid)
host = new ServiceHost(typeof(RCRServer), new Uri("net.tcp://localhost:8000"));
//notice the NetTcpBinding? This allows programs instead of web stuff
// to communicate with each other
host.AddServiceEndpoint(typeof(IMessage), new NetTcpBinding(), "ISubscribe");
try
{
host.Open();
Console.WriteLine("Successfully opened port 8000.");
//Console.ReadLine();
//host.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public bool Subscribe()
{
try
{
//Get the hashCode of the connecting app and store it as a connection
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
if (!subscribers.Contains(callback))
subscribers.Add(callback);
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
}
public bool Unsubscribe()
{
try
{
//remove any connection that is leaving
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
if (subscribers.Contains(callback))
subscribers.Remove(callback);
return true;
}
catch
{
return false;
}
}
public void AddMessage(String message)
{
//Console.WriteLine("Calling OnMessageAdded on callback");
//foreach (Subscriber s in subscribers.Values.ToList())
//{ }
try
{
Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
callback.OnMessageAdded(message, DateTime.Now);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//Go through the list of connections and call their callback funciton
//subscribers.ForEach(delegate (IMessageCallback callback)
//{
// //System.Threading.Thread.Sleep(1000);
// if (((ICommunicationObject)callback).State == CommunicationState.Opened)
// {
// Console.WriteLine("Clients connected to service " + subscribers.Count.ToString());
// callback.OnMessageAdded(message, DateTime.Now);
// }
// else
// {
// subscribers.Remove(callback);
// }
//});
}
}
}
Client:
namespace WCFClient
{
//These are the interface declerations for the client
[ServiceContract]
interface IMessageCallback
{
//This is the callback interface decleration for the client
[OperationContract(IsOneWay = true)]
void OnMessageAdded(string message, DateTime timestamp);
}
[ServiceContract(CallbackContract = typeof(IMessageCallback))]
public interface IMessage
{
//these are the interface decleratons for the server.
[OperationContract]
void AddMessage(string message);
[OperationContract]
bool Subscribe();
[OperationContract]
bool Unsubscribe();
}
class RCRProxy : IMessageCallback, IDisposable
{
IMessage pipeProxy = null;
//MainWindow mainwindow = new MainWindow();
//public RCRProxy(MainWindow main)
//{
// mainwindow = main;
//}
public bool Connect()
{
//note the "DuplexChannelFactory". This is necessary for Callbacks.
// A regular "ChannelFactory" won't work with callbacks.
DuplexChannelFactory<IMessage> pipeFactory =
new DuplexChannelFactory<IMessage>(
new InstanceContext(this),
new NetTcpBinding(),
new EndpointAddress("net.tcp://localhost:8000/ISubscribe"));
try
{
//Open the channel to the server
pipeProxy = pipeFactory.CreateChannel();
//Now tell the server who is connecting
pipeProxy.Subscribe();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
}
public void Close()
{
pipeProxy.Unsubscribe();
}
//This function sends a string to the server so that it can broadcast
// it to all other clients that have called Subscribe().
public string SendMessage(string message)
{
try
{
System.Threading.Thread.Sleep(1000);
pipeProxy.AddMessage(message);
return "sent >>>> " + message;
}
catch (Exception e)
{
return e.Message;
}
}
//This is the function that the SERVER will call
public void OnMessageAdded(string message, DateTime timestamp)
{
//Console.WriteLine(message + ": " + timestamp.ToString("hh:mm:ss"));
// mainwindow.txtblkStatus.Text = message + ": " + timestamp.ToString("hh:mm:ss");
}
//We need to tell the server that we are leaving
public void Dispose()
{
pipeProxy.Unsubscribe();
}
}
}
namespace StockTickerClient
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public class DataItem
{
public string Symbol { get; set; }
public string Series { get; set; }
public float? AskPrice { get; set; }
public float? BidPrice { get; set; }
public float? LTP { get; set; }
public int? Volume { get; set; }
public string Description { get; set; }
public DateTime? SentDate { get; set; }
public DataItem(string symbol, string series, float? askprice, float? bidprice, float? ltp, int? volume, string
description, DateTime? sentdate)
{
Symbol = symbol;
Series = series;
AskPrice = askprice;
BidPrice = bidprice;
LTP = ltp;
Volume = volume;
Description = description;
SentDate = sentdate;
}
}
public partial class MainWindow : Window
{
private void btnSubscribe_Click(object sender, RoutedEventArgs e)
{
RCRProxy rp = new RCRProxy();
if (rp.Connect() == true)
{
// Console.WriteLine("please space to end session");
string tmp = "Start";// Console.ReadLine();
while (tmp != "Exit")
{
try
{
rp.SendMessage(tmp);
}
catch (Exception ex)
{
txtblkStatus.Text = ex.Message;
}
// tmp = Console.ReadLine();
// txtblkStatus.Text = rp.SendMessage(tmp);
}
}
if (((ICommunicationObject)rp).State == CommunicationState.Opened)
rp.Close();
}
}
}
In the winforms/wpf application the communication between the server and the clients should be done on a secondary thread that is responsible of only that. If you put the action that you have on button btnSubscribe_Click in a new thread, the application will run ok.
See more details of how to work with threads in wpf:
c# wpf run button click on new thread
https://www.c-sharpcorner.com/UploadFile/1c8574/threads-in-wpf/
https://msdn.microsoft.com/en-us/library/ms741870(v=vs.85).aspx

Async Function Only Updating One "Await"

Excuse my ignorance on this subject, but I'm not schooled in asynchronous programming. However, I believe my code is close to achieving what I need it to do.
Basically the code below only works for the very first
C61 = new BridgeViewModel("C61");
await C61.Initialize();
statements. None of the other items are returning any data to the bound .xaml and I have no idea why. Does each one need to be in its own Initialize function?
Any help is greatly appreciated.
Code:
namespace SentinelApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new MainViewModel();
DataContext = vm;
vm.Initialize();
}
}
public class MainViewModel
{
public readonly string[] Bridges = { "C61", "C62", "C63", "C68", "C69", "K71", "K72", "K73", "K74", "T91", "GN01", "GE01", "GA01" };
public async Task Initialize()
{
C61 = new BridgeViewModel("C61");
await C61.Initialize();
C62 = new BridgeViewModel("C62");
await C62.Initialize();
C63 = new BridgeViewModel("C63");
await C63.Initialize();
C68 = new BridgeViewModel("C68");
await C68.Initialize();
C69 = new BridgeViewModel("C69");
await C69.Initialize();
K71 = new BridgeViewModel("K71");
await K71.Initialize();
K72 = new BridgeViewModel("K72");
await K72.Initialize();
K73 = new BridgeViewModel("K73");
await K73.Initialize();
K74 = new BridgeViewModel("K74");
await K74.Initialize();
T91 = new BridgeViewModel("T91");
await T91.Initialize();
GA01 = new BridgeViewModel("GA01");
await GA01.Initialize();
GE01 = new BridgeViewModel("GE01");
await GE01.Initialize();
GN01 = new BridgeViewModel("GN01");
await GN01.Initialize();
}
public BridgeViewModel C61 { get; set; }
public BridgeViewModel C62 { get; set; }
public BridgeViewModel C63 { get; set; }
public BridgeViewModel C68 { get; set; }
public BridgeViewModel C69 { get; set; }
public BridgeViewModel K71 { get; set; }
public BridgeViewModel K72 { get; set; }
public BridgeViewModel K73 { get; set; }
public BridgeViewModel K74 { get; set; }
public BridgeViewModel T91 { get; set; }
public BridgeViewModel GA01 { get; set; }
public BridgeViewModel GE01 { get; set; }
public BridgeViewModel GN01 { get; set; }
}
public class BridgeViewModel : ViewModel
{
private readonly ClientWrapper _client;
private readonly string _bridge;
private readonly Timer _timer = new Timer();
public BridgeViewModel(string bridge)
{
_client = new ClientWrapper();
_bridge = bridge;
}
public async Task Initialize()
{
await _client.Connect(_bridge);
await _client.SendMessage(new SessionStart("3", "25").CreateBridgeMessage());
_timer.Interval = 1000;
_timer.Elapsed += Update;
_timer.Start();
}
private async void Update(object sender, ElapsedEventArgs e)
{
try {
var response = await _client.SendMessage("BS~RESERVE~STATS~REQ~" + _bridge + "~0");
var split = response.Split('~');
Timestamp = split[4].Substring(0, 2) + ":" + split[4].Substring(2, 2) + ":" + split[4].Substring(4, 2);
FreePorts = split[6];
LongestHold = TimeSpan.FromSeconds(int.Parse(split[15])).ToString("hh:mm");
Bells = split[12];
Signals = split[8];
} catch { }
}
private string _timestamp;
public string Timestamp
{
get { return _timestamp; }
set { _timestamp = value; RaisePropertyChanged(); }
}
private string _bells;
public string Bells
{
get { return _bells; }
set { _bells = value; RaisePropertyChanged(); }
}
private string _signals;
public string Signals
{
get { return _signals; }
set { _signals = value; RaisePropertyChanged(); }
}
private string _freeports;
public string FreePorts
{
get { return _freeports; }
set { _freeports = value; RaisePropertyChanged(); }
}
private string _longesthold;
public string LongestHold
{
get { return _longesthold; }
set { _longesthold = value; RaisePropertyChanged(); }
}
}
}
Instead of using your async method inside a constructor, register and use it inside the FrameworkElement.Loaded event where you can await:
public MainWindow()
{
InitializeComponent();
Loaded += InitializeOnLoaded;
}
public async void InitializeOnLoaded(object sender, RoutedEventArgs e)
{
var vm = new MainViewModel();
DataContext = vm;
await vm.InitializeAsync();
}

C# event is null even though it is subscribed [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have a Flight class and a Form class, I want to send Log messages to a textfield from the Flight class to the Form.
I have an already working one for another class called Airport, but this one is practically identical, yet the event LogMessage is always null, even after subscribing.
-- MainForm --
namespace FlightSim
{
public partial class MainForm : Form
{
Airport airport = new Airport();
Luggage luggage = new Luggage();
Flight flight = new Flight();
DAO db = new DAO();
public MainForm()
{
InitializeComponent();
InitializeEvents();
}
private void InitializeEvents()
{
this.airport.ErrorMessage += new System.EventHandler(OnErrorReceived);
this.flight.LogMessage += new System.EventHandler(OnLogReceived);
}
public void OnErrorReceived(object sender, System.EventArgs e)
{
string msgContent = ((Airport.MessageEventArgs)e).msgContent;
this.mainLog.AppendText(msgContent);
}
public void OnLogReceived(object sender, System.EventArgs e)
{
string msgcontent = ((Flight.MessageEventArgs)e).msgContent;
this.mainLog.AppendText(msgcontent);
}
}
}
-- Flight --
namespace FlightSim
{
public class Flight
{
public class MessageEventArgs : System.EventArgs
{
public string msgContent;
}
public event System.EventHandler LogMessage;
DAO db = new DAO();
public Flight(string flightNumber, string departure, string destination, int totalLoadCapacity)
{
this.FlightNumber = flightNumber;
this.Departure = departure;
this.Destination = destination;
this.TotalLoadCapacity = totalLoadCapacity;
//LogMessage += (s, o) => { };
}
public void StartFlight()
{
string tmpDeparture = this.Departure;
string tmpDestination = this.Destination;
this.OnLogUpdate("Taking off from " + tmpDeparture + " now.");
this.Destination = tmpDeparture;
Thread.Sleep(1000);
this.OnLogUpdate("Arriving in " + tmpDestination + " now.");
this.Departure = tmpDestination;
}
protected void OnLogUpdate(string logMessage)
{
if (logMessage == "")
return;
MessageEventArgs e = new MessageEventArgs();
var handler = LogMessage;
if (handler != null)
{
e.msgContent = logMessage;
handler(this, e);
}
}
}
}
So, what can be the cause for an event being null even though it is subscribed?
Given the constructor with arguments and the initialization without arguments, you probably are creating another Flight class somewhere else. All you have to do is make sure that you subscribe the same event upon creation. Do something like this;
Flight someOtherFlight = new Flight("1", "Amsterdam", "Hong Kong", 500);
someOtherFlight.LogMessage += new System.EventHandler(OnLogReceived);
And you should be fine.
Edit: This MCVE works fine
Program.cs
namespace StackOverflowPlayground
{
class Program
{
static void Main(string[] args)
{
var sim = new AirportSim();
sim.flight.StartFlight();
}
}
}
FlightSim.cs
using System;
using System.Threading;
namespace StackOverflowPlayground
{
public class AirportSim
{
public Flight flight = new Flight("1","","",1);
public AirportSim()
{
InitializeEvents();
}
private void InitializeEvents()
{
flight.LogMessage += OnLogReceived;
}
public void OnLogReceived(object sender, System.EventArgs e)
{
string msgcontent = ((Flight.MessageEventArgs)e).msgContent;
Console.WriteLine(msgcontent);
}
}
public class Flight
{
public class MessageEventArgs : EventArgs
{
public string msgContent;
}
public event EventHandler LogMessage;
public Flight(string flightNumber, string departure, string destination, int totalLoadCapacity)
{
FlightNumber = flightNumber;
Departure = departure;
Destination = destination;
TotalLoadCapacity = totalLoadCapacity;
//LogMessage += (s, o) => { };
}
public string Destination { get; set; }
public int TotalLoadCapacity { get; set; }
public string Departure { get; set; }
public string FlightNumber { get; set; }
public void StartFlight()
{
string tmpDeparture = this.Departure;
string tmpDestination = this.Destination;
OnLogUpdate("Taking off from " + tmpDeparture + " now.");
Destination = tmpDeparture;
Thread.Sleep(1000);
OnLogUpdate("Arriving in " + tmpDestination + " now.");
Departure = tmpDestination;
}
protected void OnLogUpdate(string logMessage)
{
if (logMessage == "")
return;
var e = new MessageEventArgs();
var handler = LogMessage;
if (handler != null)
{
e.msgContent = logMessage;
handler(this, e);
}
}
}
}

wb.DownloadFileAsync throw "WebClient does not support concurrent I/O operations." exception

I need help with this code
#region Events
public class DownloadProgressChangedEventArg
{
private long _ProgressPercentage;
private long _BytesReceived;
private long _TotalBytesToReceive;
public DownloadProgressChangedEventArg(long BytesReceived, long TotalBytesToReceive)
{
_BytesReceived = BytesReceived;
_TotalBytesToReceive = TotalBytesToReceive;
_ProgressPercentage = BytesReceived * 100 / (TotalBytesToReceive);
}
public long BytesReceived { get { return _BytesReceived; } set { _BytesReceived = value; } }
public long ProgressPercentage { get { return _ProgressPercentage; } set { _ProgressPercentage = value; } }
public long TotalBytesToReceive { get { return _TotalBytesToReceive; } set { _TotalBytesToReceive = value; } }
}
public delegate void DownloadProgressChangedEventHandler(Api.GetSong.GetObject.Object Sender, DownloadProgressChangedEventArg e);
public event DownloadProgressChangedEventHandler DownloadProgressChangedEvent;
public class DownloadCompletedEventArg
{
private bool _Cancelled;
private Exception _Error;
public DownloadCompletedEventArg(Exception Error, bool Cancelled)
{
_Cancelled = Cancelled;
_Error = Error;
}
public bool Cancelled { get { return _Cancelled; } set { _Cancelled = value; } }
public Exception Error { get { return _Error; } set { _Error = value; } }
}
public delegate void DownloadCompletedEventHandler(Api.GetSong.GetObject.Object Sender, DownloadCompletedEventArg e);
public event DownloadCompletedEventHandler DownloadCompletedEvent;
#endregion
WebClient wb;
public void DownloadFileAsync(Api.GetSong.GetObject.Object Object, String FileLocation)
{
String DownloadLink = GetStreamUri(Object);
String FileTitle = Object.Title + "." + Object.Type;
String FileLocations = Path.Combine(FileLocation,FileTitle);
if (!DownloadLink.StartsWith("rtmp"))
{
if (wb == null)
{
wb = new WebClient();
wb.DownloadFileCompleted += delegate(object sender, AsyncCompletedEventArgs e) { DownloadCompletedEvent(Object, new DownloadCompletedEventArg(e.Error, e.Cancelled)); };
wb.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e) { DownloadProgressChangedEvent(Object, new DownloadProgressChangedEventArg(e.BytesReceived, e.TotalBytesToReceive)); };
}
wb.DownloadFileAsync(new Uri(DownloadLink), FileLocations);
//throw:
//WebClient does not support concurrent I/O operations.
}
else
{
//Düzenlencek
}
}
public void DownloadFileCancel()
{
if (wb.IsBusy && wb != null)
{
wb.CancelAsync();
}
}
When calling DownloadFileAsync method you have to make sure it completes before trying to download again.
This answer will help you.

Invoke a delegate on the main thread in a tiered architecture

I have a background process that i want to regularly maintain the state of gps location. I am not clear on how to invoke a delegate on the main thread in the ui layer when the threaded method is in another class. Here is sample code. My form launches the thread on load:
public partial class MainScreen : Form
{
.
. // form stuff
.
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
Thread t = new Thread(gpsStatusManager.UpdateLocation);
t.IsBackground = true;
t.Start();
}
delegate void GpsDataParameterDelegate(GpsStatus value);
public void UpdateGpsStatus(GpsStatus value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
gpsStatus.SetGpsStatus(value);
}
}
I have a domain object class for the gps information:
public class GpsStatus
{
public void SetGpsStatus(GpsStatus gpsStatus)
{
Latitude = gpsStatus.Latitude;
Longitude = gpsStatus.Longitude;
CurrentDateTime = gpsStatus.CurrentDateTime;
NumberOfSatellites = gpsStatus.NumberOfSatellites;
TotalNumberSatellites = gpsStatus.TotalNumberSatellites;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
public DateTime CurrentDateTime { get; private set; }
public int NumberOfSatellites { get; private set; }
public int TotalNumberSatellites { get; private set; }
}
Then, my manager class where i update status in the secondary thread:
public class GpsStatusManager
{
private GpsStatus _gpsStatus;
public void UpdateLocationx()
{
while (UpdateGpsData())
{
Thread.Sleep(2000);
}
}
private bool UpdateGpsData()
{
SError error;
SGpsPosition gpsPosition;
try
{
if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1)
return false;
}
catch (Exception)
{
return false;
}
var numberOfSatellites = gpsPosition.Satellites;
var totalSatellites = gpsPosition.satellitesInfo;
var datetime = gpsPosition.Time;
var lat = gpsPosition.Latitude;
var lon = gpsPosition.Longitude;
_gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites);
//How do I invoke the delegate to send the _gpsStatus data to my main thread?
return true;
}
}
Thanks for any assistance.
Here's one way to do it, just off the top of my head:
public class GpsStatusEventArgs : EventArgs
{
public GpsStatus Status { get; private set; }
public GpsStatusEventArgs(GpsStatus status)
{
Status = status;
}
}
public class GpsStatusManager
{
...
public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated;
private void OnGpsStatusUpdated(GpsStatus gpsStatus)
{
EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated;
if (temp != null)
temp.Invoke(this, new GpsStatusEventArgs(gpsStatus));
}
}
public partial class MainScreen : Form
{
...
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated);
...
}
private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e)
{
UpdateGpsStatus(e.Status);
}
...
}
Then add this to the bottom of UpdateGpsData:
OnGpsStatusUpdated(_gpsStatus);
You should use the SynchronizationContext class.
In the UI thread (in any class), set a field (perhaps static) to SynchronizationContext.Current.
You can then call Send or Post on the saved instance to execute code on the UI thread.
Here is another approach using the ISynchronizeInvoke interface. This is the same pattern the System.Timers.Timer class uses to raise the Elapsed event.
public class GpsStatusManager
{
public ISynchronizeInvoke SynchronizingObject { get; set; }
public event EventHandler Update;
public void UpdateGpsData()
{
// Code omitted for brevity.
OnUpdate(_gpsStatus);
return true;
}
private OnUpdate(GpsStatus status)
{
if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired)
{
ThreadStart ts = () => { OnUpdate(status); };
SynchronizingObject.Invoke(ts, null);
}
else
{
if (Update != null)
{
Update(this, status);
}
}
}
public class UpdateEventArgs : EventArgs
{
public GpsStatus Status { get; set; }
}
}

Categories