I am writing a wpf application to control an embedded device over TCP. Writing to the device is easy, but I am having trouble receiving packets.
I have created a tcp NetworkStream and am using NetworkStream.BeginRead() to listen for TCP data. However, once I have composed a full packet, I would like to update my GUI to reflect the new information. It seems that I am not allowed to do this from the asynchronous callback thread.
It appears that there is a way to do this through the dispatcher one request at a time, but I need to update practically every control on my GUI. I am not writing a dispatcher function for every packet case and every WPF control. How do I get complete access to the WPF controls from my asynchronous thread?
EDIT: Here is a code sample:
NetworkUnion union = (NetworkUnion)ar.AsyncState;
union.BytesRead += tcpStream.EndRead(ar);
if (union.BytesRead < union.TargetSize)
tcpStream.BeginRead(union.ByteArray, union.BytesRead, union.TargetSize - union.BytesRead, new AsyncCallback(ReadCommandCallback), union);
else
{
NetworkUnion payload = new NetworkUnion();
NetworkPacket pkt = (NetworkPacket)union.getArrayAsStruct();
// Respond to the packet
// Read the payload
payload.ByteArray = new byte[pkt.payloadSize];
tcpStream.Read(payload.ByteArray, 0, pkt.payloadSize);
// Determine what the payload is!
switch (pkt.code)
{
case (int)PacketCode.STATE:
payload.ObjectType = typeof(NetworkState);
NetworkState state = (NetworkState)payload.getArrayAsStruct();
Handle.fuelGauge.Value = Convert.ToDouble(state.mainFuel);
break;
When I try to update the fuel gauge, I get an InvalidOperationException, calling thread cannot access because another thread owns the object
The 'Handle' variable is used because this is from within a static utility class
The main question is, do I really have to replace every line of
Handle.fuelGauge.Value = Convert.ToDouble(state.mainFuel);
with
Handle.fuelGauge.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
Handle.fuelGauge.Value = Convert.ToDouble(state.mainFuel);
}
));
? It seems excessively repetitive. It would be easier to do something like:
Handle.mainWindow.Dispather.Lock();
Handle.fuelGauge.Value = Convert.ToDouble(state.mainFuel);
change everything else...
Handle.mainWindow.Dispatcher.Unlock();