My problem might be a dumb one but after hours of searching, I have to ask you for help.
I have a WPF form LoginPage that features a Label ,(called AlertText) that displays messages to the user and I need to change his content from another class.
To change the content I use AlertText.Content = "content" and it works perfectly.
But when I'm on another class and I want to change it that doesn't do anything.
Both class are under the same namespace.
I've tried this :
LoginPage lg = new LoginPage();
lg.AlertText.Content = "content";
The object is created but the second line isn't executed.
I've tried to create a public function SetAlertText() in my LoginPage class but that doesn't worked either.
I made it static and called it by LoginPage.SetAlertText() but same problem persists.
I've added this in my LoginPage :
public static LoginPage instance;
public LoginPage()
{
instance = this;
}
And called it by
LoginPage.instance.SetAlertText();
and
LoginPage.instance.AlertText.Content = "content";
but neither worked.
I also tried :
public LoginPage()
{
instance = new LoginPage();
}
What can I do ?
Edit :
Here's the full code of both classes :
namespace TMClientWPF
{
/// <summary>
/// Logique d'interaction pour LoginPage.xaml
/// </summary>
public partial class LoginPage : Page
{
ClientTCP client;
bool isConnected = false;
public RegisterPage registerPage;
public static LoginPage instance;
public LoginPage()
{
instance = this;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
AlertText.Content = "";
try
{
if (isConnected == false)
{
client = new ClientTCP();
client.Connect();
isConnected = true;
}
client.SEND_LOGINS(UsernameText.Text, PasswordText.Password.ToString());
}
catch (NullReferenceException)
{
AlertText.Visibility = Visibility.Visible;
AlertText.Content = "Failed to connect to server, please try again later.";
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
registerPage = new RegisterPage();
this.NavigationService.Navigate(registerPage);
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
public void SetAlertText(string text)
{
AlertText.Visibility = Visibility.Visible;
AlertText.Content = "Welcome Home";
}
}
}
///////////////////////////////
namespace TMClientWPF
{
public class ClientHandlePackets
{
public static ByteBuffer playerBuffer;
private delegate void Packet_(byte[] data);
private static Dictionary<long, Packet_> packets;
private static long pLength;
public static void HandleData(byte[] data)
{
InitializePackets();
byte[] Buffer;
Buffer = (byte[])data.Clone();
if (playerBuffer == null)
{
playerBuffer = new ByteBuffer();
}
playerBuffer.WriteBytes(Buffer);
if (playerBuffer.Count() == 0)
{
playerBuffer.Clear();
return;
}
if (playerBuffer.Length() >= 8)
{
pLength = playerBuffer.ReadLong(false);
if (pLength <= 0)
{
playerBuffer.Clear();
return;
}
}
while (pLength > 0 & pLength <= playerBuffer.Length() - 8)
{
if (pLength <= playerBuffer.Length() - 8)
{
playerBuffer.ReadLong(); //read out the packet identifier
data = playerBuffer.ReadBytes((int)pLength); //get the full package length
HandleDataPackets(data);
}
pLength = 0;
if (playerBuffer.Length() >= 8)
{
pLength = playerBuffer.ReadLong(false);
if (pLength < 0)
{
playerBuffer.Clear();
return;
}
}
}
}
private static void HandleDataPackets(byte[] data)
{
long packetIdentifier;
ByteBuffer buffer;
Packet_ packet;
buffer = new ByteBuffer();
buffer.WriteBytes(data);
packetIdentifier = buffer.ReadLong();
buffer.Dispose();
if (packets.TryGetValue(packetIdentifier, out packet))
{
packet.Invoke(data);
}
}
private static void InitializePackets()
{
packets = new Dictionary<long, Packet_>();
packets.Add((long)ServerPackets.S_INFORMATION, PACKET_INFORMATION);
packets.Add((long)ServerPackets.S_EXECUTEMETHODONCLIENT, PACKET_EXECUTEMETHOD);
packets.Add((long)ServerPackets.S_LOGCALLBACK, Packet_LogCallback);
}
#region packets
private static void PACKET_INFORMATION(byte[] data)
{
ByteBuffer buffer = new ByteBuffer();
buffer.WriteBytes(data);
long packetIndentifier = buffer.ReadLong();
string msg1 = buffer.ReadString();
string msg2 = buffer.ReadString();
int level = buffer.ReadInteger();
buffer.Dispose();
ClientTCP.instance.SEND_THANKYOU();
}
private static void PACKET_EXECUTEMETHOD(byte[] data)
{
ClientTCP client = new ClientTCP();
}
private static void Packet_LogCallback(byte[] data)
{
ByteBuffer buffer = new ByteBuffer();
buffer.WriteBytes(data);
buffer.ReadLong();
string message = buffer.ReadString();
string username = buffer.ReadString();
buffer.Dispose();
if(message == "true")
{
// LoginPage.SetAlertText("Welcome Home.");
}
else
{
LoginPage lg = new LoginPage();
LoginPage.instance.SetAlertText("Invalid logins.");
}
}
#endregion
}
}
Related
I have a WPF (.NET Framework 4.6) application that uses websocket-sharp (version 3.0.0) to create a websocket server.
I have a WebsocketServer and using EventHandler to tranfer event to MainWindow.xaml.cs but it not working. The MainWindow.xaml.cs listened to a RaiseOnScanDevice event but not any event invoked here.
I think this issue is relative to different thread. I try using Dispatcher.Invoke but it still not working.
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
RaiseOnScanDevice(this, new EventArgs());
}));
I found an issue (https://github.com/sta/websocket-sharp/issues/350) but the answers do not resolve my issue.
Please help me a solution for this issue.
WebsocketServer.cs file
public class WebsocketServer : WebSocketBehavior
{
private static readonly Lazy<WebsocketServer> lazyInstance = new Lazy<WebsocketServer>(() => new WebsocketServer());
public static WebsocketServer Instance
{
get
{
return lazyInstance.Value;
}
}
private const string TAG = "WebsocketServer";
private const string HOST_IP_ADDRESS = "127.0.0.2"; // localhost
private const int PORT = 38001;
public WebSocketServer socket;
private PacketHandler packetHandler = new PacketHandler();
public event EventHandler<EventArgs> RaiseOnScanDevice = new EventHandler<EventArgs>((a, e) => { });
public WebsocketServer()
{
Initialize();
}
public void Initialize()
{
socket = new WebSocketServer(IPAddress.Parse(HOST_IP_ADDRESS), PORT);
socket.AddWebSocketService<WebsocketServer>("/");
StartServer();
}
public void StartServer()
{
socket.Start();
}
public void StopServer()
{
socket.Stop();
}
protected override Task OnOpen()
{
return base.OnOpen();
}
protected override Task OnClose(CloseEventArgs e)
{
return base.OnClose(e);
}
protected override Task OnError(ErrorEventArgs e)
{
return base.OnError(e);
}
protected override Task OnMessage(MessageEventArgs e)
{
System.IO.StreamReader reader = new System.IO.StreamReader(e.Data);
string message = reader.ReadToEnd();
//Converting the event back to 'eventName' and 'JsonPayload'
PacketModel packet = packetHandler.OpenPacket(message);
HandleMessageFromClient(packet);
return base.OnMessage(e);
}
private void HandleMessageFromClient(PacketModel packet) {
var eventName = packet.EventName;
var data = packet.Data;
if (eventName == null || eventName.Equals(""))
{
return;
}
switch (eventName)
{
case SocketEvent.Hello:
Send("OK");
break;
case SocketEvent.ScanDevice:
ScanDevice();
break;
default:
break;
}
}
private void ScanDevice()
{
try
{
RaiseOnScanDevice(this, new EventArgs());
// or dispatch to Main Thread
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
RaiseOnScanDevice(this, new EventArgs());
}));
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
MainWindow.xaml.cs file
public partial class MainWindow : Window
{
public WebsocketServer WebsocketConnection
{
get { return WebsocketServer.Instance; }
}
public MainWindow()
{
InitializeComponent();
WebsocketConnection.RaiseOnScanDevice += SocketConnection_RaiseOnScanDevice;
}
private void SocketConnection_RaiseOnScanDevice(object sender, EventArgs e)
{
Console.WriteLine("SocketConnection_RaiseOnScanDevice");
}
The queue of messages is a good idea but you may want to use a lock to guard access to it. Most likely it won't be an issue but if you don't, you leave yourself open to the possibility of an error if the coroutine is reading from the queue as the websocket is writing to it. For example you could do something like this:
var queueLock = new object();
var queue = new Queue<MyMessageType>();
// use this to read from the queue
MyMessageType GetNextMessage()
{
lock (queueLock) {
if (queue.Count > 0) return queue.Dequeue();
else return null;
}
}
// use this to write to the queue
void QueueMessage(MyMessageType msg)
{
lock(queueLock) {
queue.Enqueue(msg);
}
}
I am trying to save the image from the camera as mp4(etc) on WPF application. But so far I have not been successful.
Thanks for your help.
Sorry for my bad english at first.I am receiving the image from the webcam. Below are the codes.
public partial class MainWindow : Window
{
private FilterInfoCollection cihazlar;
private VideoCaptureDevice yakala_resim
;
public MainWindow()
{
InitializeComponent();
cihazlar = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo device in cihazlar)
{
kameralar.Items.Add(device.Name);
kameralar.SelectedIndex = 2;
}
}
private void Başla_Click(object sender, RoutedEventArgs e)
{
yakala_resim = new VideoCaptureDevice(cihazlar[kameralar.SelectedIndex].MonikerString);
yakala_resim.NewFrame += Yakala_NewFrame1;
yakala_resim.Start();
}
private void Yakala_NewFrame1(object sender, NewFrameEventArgs eventArgs)
{
try
{
BitmapImage bi;
using (var bitmap = (Bitmap)eventArgs.Frame.Clone())
{
bi = bitmap.ToBitmapImage();
}
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate { video.Source = bi; }));
}
catch (Exception)
{
}
}
no problem currently. But I don't know what to do when I want to save the image come from webcam as mp4.
You can use from OpenCvSharp
namespace BlackBears.Recording
{
using System;
using System.Drawing;
using System.Threading;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Size = OpenCvSharp.Size;
public class Recorder : IDisposable
{
private readonly VideoCaptureAPIs _videoCaptureApi = VideoCaptureAPIs.DSHOW;
private readonly ManualResetEventSlim _writerReset = new(false);
private readonly VideoCapture _videoCapture;
private VideoWriter _videoWriter;
private Thread _writerThread;
private bool IsVideoCaptureValid => _videoCapture is not null && _videoCapture.IsOpened();
public Recorder(int deviceIndex, int frameWidth, int frameHeight, double fps)
{
_videoCapture = VideoCapture.FromCamera(deviceIndex, _videoCaptureApi);
_videoCapture.Open(deviceIndex, _videoCaptureApi);
_videoCapture.FrameWidth = frameWidth;
_videoCapture.FrameHeight = frameHeight;
_videoCapture.Fps = fps;
}
/// <inheritdoc />
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
~Recorder()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
StopRecording();
_videoCapture?.Release();
_videoCapture?.Dispose();
}
}
public void StartRecording(string path)
{
if (_writerThread is not null)
return;
if (!IsVideoCaptureValid)
ThrowHelper.ThrowVideoCaptureNotReadyException();
_videoWriter = new VideoWriter(path, FourCC.XVID, _videoCapture.Fps, new Size(_videoCapture.FrameWidth, _videoCapture.FrameHeight));
_writerReset.Reset();
_writerThread = new Thread(AddCameraFrameToRecordingThread);
_writerThread.Start();
}
public void StopRecording()
{
if (_writerThread is not null)
{
_writerReset.Set();
_writerThread.Join();
_writerThread = null;
_writerReset.Reset();
}
_videoWriter?.Release();
_videoWriter?.Dispose();
_videoWriter = null;
}
private void AddCameraFrameToRecordingThread()
{
var waitTimeBetweenFrames = (int)(1_000 / _videoCapture.Fps);
using var frame = new Mat();
while (!_writerReset.Wait(waitTimeBetweenFrames))
{
if (!_videoCapture.Read(frame))
return;
_videoWriter.Write(frame);
}
}
}
}
Recording Video from Webcam with OpenCvSharp - Resulting File playback to fast
I'm trying to develop a warning if I try to connect to a specific SSID and some waiting time has passed. I've tried with a Timer class but there is some issues with Task and Threads I can't resolve.
This is my Wifi class in Xamarin.Droid
public class Wifi : Iwifi
{
private Context context;
private static WifiManager _manager;
private MyReceiver _receiver;
public void Initialize()
{
context = Android.App.Application.Context;
_manager = (WifiManager)context.GetSystemService(Context.WifiService);
_receiver = new MyReceiver();
}
public void Register()
{
IntentFilter intents = new IntentFilter();
intents.AddAction(WifiManager.ScanResultAction);
intents.AddAction(WifiManager.NetworkStateChangedAction);
context.RegisterReceiver(_receiver, intents);
}
public void Unregister()
{
context.UnregisterReceiver(_receiver);
}
public void ScanWirelessDevices()
{
_manager.StartScan();
}
public string GetConnectionSSID()
{
return _manager.ConnectionInfo.SSID;
}
public void ConnectToSSID(string SSID, string pwd)
{
if (!_manager.IsWifiEnabled)
{
_manager.SetWifiEnabled(true);
}
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.Ssid = '"' + SSID + '"';
if (pwd.Empty)
{
wifiConfiguration.AllowedKeyManagement.Set((int)KeyManagementType.None);
}
else
{
//Configuration for protected Network
}
var addNet = _manager.AddNetwork(wifiConfiguration);
if (addNet == -1)
{
_manager.Disconnect();
_manager.EnableNetwork(addNet, true);
_manager.Reconnect();
return;
}
var list = _manager.ConfiguredNetworks;
foreach (WifiConfiguration conf in list)
{
if (conf.Ssid.Equals('"' + SSID + '"'))
{
_manager.Disconnect();
_manager.EnableNetwork(conf.NetworkId, true);
_manager.Reconnect();
return;
}
}
}
public class MyReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action.Equals(WifiManager.ScanResultAvailableAction))
{
IList<ScanResult> scanResult = _manager.ScanResult;
App.Networks.NetworksList.Clear();
foreach (ScanResult result in scanResult)
{
App.Networks.NetworksList.Add(result.Ssid);
}
}
}
}
}
Then this is a part of App class in Xamarin.Forms
public partial class App: Application
{
private static ...
.
.
.
private static string _selectedSSID;
private static MainDetail _pageDetail;
public static IWifi WifiManager { get; } = DependencyService.Get<Iwifi>();
public static string SelectedSSID { get { return _selectedSSID; } set { _selectedSSID = value; } }
public static MainDetail PageDetail { get { return _pageDetail; } }
public App()
{
InitializeComponent();
WifiManager.Initialize();
WifiManager.Register();
InitViews();
MainPage = _mainPage;
Connectivity.ConnectivityChanged += NetworkEvents;
NetSearch();
}
.
.
.
public void NetSearch()
{
Task.Run(async () =>
{
while (true)
{
WifiManager.ScanWirelessDevices();
await Task.Delay(Utility.SCAN_WIFI_TIMER); //waiting 31000 milliseconds because of Scanning throttling
}
});
}
public void NetworkEvents(object sender, ConnectivityChangedEventArgs e)
{
MainMaster master = (MainMaster)_mainPage.Master;
if (e.NetworkAccess == NetworkAccess.Unknown)
{
Debug.WriteLine("Network Access Unknown " + e.ToString());
}
if (e.NetworkAccess == NetworkAccess.None)
{
Debug.WriteLine("Network Access None " + e.ToString());
}
if (e.NetworkAccess == NetworkAccess.Local)
{
Debug.WriteLine("Network Access Local " + e.ToString());
}
if (e.NetworkAccess == NetworkAccess.Internet)
{
if(selectedSSID == Wifimanager.GetConnectionInfo())
{
//WE CONNECTED!!
//Now I want to stop the Timeout Timer to attempt
}
}
if (e.NetworkAccess == NetworkAccess.ConstrainedInternet)
{
Debug.WriteLine("Network Access Constrainde Internet " + e.ToString());
}
}
}
And part of Detail page class in which I start the event of connection and where I want to start also the timeout timer
public partial class MainDetail : ContentPage
{
.
.
.
public void OnItemListClicked(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
ImageCell item = (ImageCell)e.SelectedItem;
App.SelectedSSID = item.Text;
App.WifiManager.ConnectToSSID(item.Text, "");
ActivityIndicator(true);
//Now the timer should start.
//And call PageDetail.ActivityIndicator(false) and warning the user if the timeout go to 0.
listView.SelectedItem = null;
}
}
I tried with the Timers Timer class but doesn't work.. any suggestion?
Ok I figured a solution! Instead of using Thread and Task, I used Device.StartTimer.
In the event on the DetailPage I wrote:
public void OnItemListClicked(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
ImageCell item = (ImageCell)e.SelectedItem;
App.SelectedSSID = item.Text;
App.WifiManager.ConnectToSSID(item.Text, "");
ActivityIndicator(true);
Device.StartTimer(TimeSpan.FromSeconds(10), () => //Waiting 10 second then if we are not connected fire the event.
{
Device.BeginInvokeOnMainThread(() =>
{
if (App.IsLogout) //variable I use to check if I can do the logout or not
{
ActivityIndicator(false);
App.SelectedSSID = "";
//My message to users "Fail to connect"
}
});
return false;
});
listView.SelectedItem = null;
}
I have a v4.0.0.1 implementation of Somdron's "Reliable Pub-Sub" pattern for communication between two parts of a new application. This application will have a "Server" (the engine that does all the heavy calculations) and "Clients" that will send requests and get information on progress back from the server.
The problem I have with my current version of "Reliable Pub-Sub" is that I don't seem to have a proper way for sending requests to the sever from the client. Let me start by showing you the code:
SERVER:
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Linq;
namespace Demo.Messaging.Server
{
public class ZeroMqMessageServer : IDisposable
{
private const string WELCOME_MESSAGE = "WM";
private const string HEARTBEAT_MESSAGE = "HB";
private const string PUBLISH_MESSAGE_TOPIC = "PUB";
private readonly TimeSpan HEARTBEAT_INTERVAL = TimeSpan.FromSeconds(2);
private NetMQActor actor;
private NetMQTimer heartbeatTimer;
private XPublisherSocket publisher;
private NetMQPoller poller;
public ZeroMqMessageServer(string address)
{
Address = address;
actor = NetMQActor.Create(Start);
}
private void Start(PairSocket shim)
{
using (publisher = new XPublisherSocket())
{
publisher.SetWelcomeMessage(WELCOME_MESSAGE);
publisher.Bind(Address);
//publisher.ReceiveReady -= DropPublisherSubscriptions;
publisher.ReceiveReady += DropPublisherSubscriptions;
heartbeatTimer = new NetMQTimer(HEARTBEAT_INTERVAL);
heartbeatTimer.Elapsed += OnHeartbeatTimeElapsed;
shim.ReceiveReady += OnShimReceiveReady;
shim.SignalOK(); // Let the actor know we are ready to work.
poller = new NetMQPoller() { publisher, shim, heartbeatTimer };
poller.Run();
}
}
private void DropPublisherSubscriptions(object sender, NetMQSocketEventArgs e)
{
publisher.SkipMultipartMessage();
}
private void OnHeartbeatTimeElapsed(object sender, NetMQTimerEventArgs e)
{
publisher.SendFrame(HEARTBEAT_MESSAGE);
}
private void OnShimReceiveReady(object sender, NetMQSocketEventArgs e)
{
var socket = e.Socket;
string command = socket.ReceiveFrameString();
if (command == PUBLISH_MESSAGE_TOPIC)
{
// Forward the message to the publisher.
NetMQMessage message = socket.ReceiveMultipartMessage();
publisher.SendMultipartMessage(message);
}
else if (command == NetMQActor.EndShimMessage)
{
// Dispose command received, stop the poller.
poller.Stop();
}
}
public void PublishMessage(NetMQMessage message)
{
// We can use actor like NetMQSocket and publish messages.
actor.SendMoreFrame(PUBLISH_MESSAGE_TOPIC)
.SendMultipartMessage(message);
}
public string Address { get; private set; }
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
actor?.Dispose();
publisher?.Dispose();
poller?.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
}
CLIENT:
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Collections.Generic;
using System.Linq;
using Messaging.Helpers;
namespace Demo.Messaging.Client
{
public class ZeroMqMessageClient : IDisposable
{
private string SUBSCRIBE_COMMAND = "S";
private const string WELCOME_MESSAGE = "WM";
private const string HEARTBEAT_MESSAGE = "HB";
private const string PUBLISH_MESSAGE_TOPIC = "PUB";
private readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(5);
private readonly TimeSpan RECONNECTION_PERIOD = TimeSpan.FromSeconds(5);
private readonly string[] addressCollection;
private List<string> subscriptions = new List<string>();
private NetMQTimer timeoutTimer;
private NetMQTimer reconnectionTimer;
private NetMQActor actor;
private SubscriberSocket subscriber;
private PairSocket shim;
private NetMQPoller poller;
public ZeroMqMessageClient(params string[] addresses)
{
addressCollection = addresses;
actor = NetMQActor.Create(Start);
}
private void Start(PairSocket shim)
{
this.shim = shim;
shim.ReceiveReady += OnShimReceiveReady;
timeoutTimer = new NetMQTimer(TIMEOUT);
timeoutTimer.Elapsed += OnTimeoutTimerElapsed;
reconnectionTimer = new NetMQTimer(RECONNECTION_PERIOD);
reconnectionTimer.Elapsed += OnReconnectionTimerElapsed;
poller = new NetMQPoller() { shim, timeoutTimer, reconnectionTimer };
shim.SignalOK();
Connect();
poller.Run();
if (subscriber != null)
subscriber.Dispose();
}
private void Connect()
{
using (NetMQPoller tmpPoller = new NetMQPoller())
{
List<SubscriberSocket> socketCollection = new List<SubscriberSocket>();
SubscriberSocket connectedSocket = null;
EventHandler<NetMQSocketEventArgs> messageHandler = (s, e) =>
{
connectedSocket = (SubscriberSocket)e.Socket;
tmpPoller.Stop();
};
// We cancel the poller without setting the connected socket.
NetMQTimer tmpTimeoutTimer = new NetMQTimer(TIMEOUT);
tmpTimeoutTimer.Elapsed += (s, e) => tmpPoller.Stop();
tmpPoller.Add(tmpTimeoutTimer);
// Attempt to subscribe to the supplied list of addresses.
foreach (var address in addressCollection)
{
SubscriberSocket socket = new SubscriberSocket();
socketCollection.Add(socket);
//socket.ReceiveReady -= messageHandler;
socket.ReceiveReady += messageHandler;
tmpPoller.Add(socket);
// Subscribe to welcome messages.
socket.Subscribe(WELCOME_MESSAGE);
socket.Connect(address);
}
tmpPoller.Run(); // Block and wait for connection.
// We should have an active socket/conection.
if (connectedSocket != null)
{
// Remove the connected socket from the collection.
socketCollection.Remove(connectedSocket);
ZeroMqHelpers.CloseConnectionsImmediately(socketCollection);
// Set the active socket.
subscriber = connectedSocket;
//subscriber.SkipMultipartMessage(); // This skips the welcome message.
// Subscribe to subscriptions.
subscriber.Subscribe(HEARTBEAT_MESSAGE);
foreach (var subscription in subscriptions)
subscriber.Subscribe(subscription);
// Remove start-up handler, now handle messages properly.
subscriber.ReceiveReady -= messageHandler;
subscriber.ReceiveReady += OnSubscriberReceiveReady;
poller.Add(subscriber);
// Reset timers.
timeoutTimer.Enable = true;
reconnectionTimer.Enable = false;
}
else // We need to attempt re-connection.
{
// Close all existing connections.
ZeroMqHelpers.CloseConnectionsImmediately(socketCollection);
timeoutTimer.Enable = false;
reconnectionTimer.Enable = true;
}
}
}
private void OnShimReceiveReady(object sender, NetMQSocketEventArgs e)
{
string command = e.Socket.ReceiveFrameString();
if (command == NetMQActor.EndShimMessage)
{
poller.Stop();
}
else if (command == SUBSCRIBE_COMMAND)
{
string topic = e.Socket.ReceiveFrameString();
subscriptions.Add(topic);
if (subscriber != null)
subscriber.Subscribe(topic);
}
}
private void OnTimeoutTimerElapsed(object sender, NetMQTimerEventArgs e)
{
if (subscriber != null)
{
poller.Remove(subscriber);
subscriber.Dispose();
subscriber = null;
Connect();
}
}
private void OnReconnectionTimerElapsed(object sender, NetMQTimerEventArgs e)
{
// We re-attempt connection.
Connect();
}
private void OnSubscriberReceiveReady(object sender, NetMQSocketEventArgs e)
{
// Here we just forwward the message on to the actor.
var message = subscriber.ReceiveMultipartMessage();
string topic = message[0].ConvertToString();
// Let us see what is in the message.
if (message.Count() > 1)
{
string content = message[1].ConvertToString();
Console.WriteLine($"ZMQ_ALT - {topic}:: {content}");
}
if (topic == WELCOME_MESSAGE)
{
// Disconnection has occurred we might want to restore state from a snapshot.
}
else if (topic == HEARTBEAT_MESSAGE)
{
// We got a heartbeat, lets postponed the timer.
timeoutTimer.Enable = false;
timeoutTimer.Enable = true;
}
else
{
shim.SendMultipartMessage(message);
}
}
public void Subscribe(string topic)
{
actor.SendMoreFrame(SUBSCRIBE_COMMAND).SendFrame(topic);
}
public NetMQMessage ReceiveMessage()
{
return actor.ReceiveMultipartMessage();
}
public void PublishMessage(NetMQMessage message)
{
actor.SendMoreFrame(PUBLISH_MESSAGE_TOPIC)
.SendMultipartMessage(message);
}
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
actor?.Dispose();
subscriber?.Dispose();
shim?.Dispose();
poller?.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
}
Now, I can send messages from the server to the client which is awesome and the client using the following code from the main method in two separate console applications
Program.cs for SERVER:
class Program
{
static void Main(string[] args)
{
using (ZeroMqMessageServer server = new ZeroMqMessageServer("tcp://127.0.0.1:6669"))
{
while (true)
{
NetMQMessage message = new NetMQMessage();
message.Append("A");
message.Append(new Random().Next().ToString());
server.PublishMessage(message);
Thread.Sleep(200);
}
}
}
}
Program.cs for CLIENT:
class Program
{
static void Main(string[] args)
{
Task.Run(() =>
{
using (ZeroMqMessageClient client = new ZeroMqMessageClient("tcp://127.0.0.1:6669"))
{
client.Subscribe(String.Empty);
while (true) { }
}
});
Console.ReadLine();
}
}
The client correctly auto-detects dropped connections and reconnects, fantastic little pattern.
However, this pattern out-of-the-box does not allow the client to send messages to the server. So in the client I have added the following code
public void PublishMessage(NetMQMessage message)
{
actor.SendMoreFrame(PUBLISH_MESSAGE_TOPIC)
.SendMultipartMessage(message);
}
and in the client I have changed the publisher.ReceiveReady += DropPublisherSubscriptions; event handler to
private void DropPublisherSubscriptions(object sender, NetMQSocketEventArgs e)
{
var message = e.Socket.ReceiveMultipartMessage();
string topic = message[0].ConvertToString();
Console.WriteLine($"TOPIC = {topic}");
// Let us see what is in the message.
if (message.Count() > 1)
{
string content = message[1].ConvertToString();
Console.WriteLine($"TEST RECIEVE FROM CLIENT - {topic}:: {content}");
}
publisher.SkipMultipartMessage();
}
but this does not seem to handle my messages. It receives the heartbeats and welcome messages, but I am not doing this right.
How can I enable/facilitate the client to talk to the server without breaking what I have already?
Thanks for your time.
I'm working on a C# UWP APP and I need to communicate with many devices using
an USB port as Serial Port. After that I will convert the communication to RS485 to communicate with the other devices. Until now, I have create a class that will make all comunications between my devices and I can sent a trama between my devices.
My problem at this point is that after sending some startup frames, the application changes the page and from that moment gives me the following exception in my ReadAsync method:
**
System.Exception occurred HResult=-2147023901 Message=The I/O
operation was canceled due to a module output or an application
request. (Exception from HRESULT: 0x800703E3) Source=mscorlib
StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at DrDeliver.CComm.d__31.MoveNext() InnerException:
**
Exception Picture
I already have this problem for a few days and I can't get over it.
I wonder if anyone can figure out where the problem is.
Another question I would like to ask is if anyone knows of any method that allows me to make this communication synchronously.
UPDATE 1
The entire class for communicatons:
public class CComm : IDisposable
{
EventLogDB _eldb = new EventLogDB();
ParameterDB _pdb = new ParameterDB();
cParameter _cParam = new cParameter();
DataReader _dataReaderObject = null;
private DispatcherTimer mTimer;
private int num;
public bool FlagComm { set; get; }
public static string InBuffer { set; get; }
public bool busyFlag = false;
public CancellationTokenSource _readCancellationTokenSource = new CancellationTokenSource();
private DeviceInformationCollection DeviceInformation { set; get; }
private static SerialDevice SerialPort { set; get; }
// Define a delegate
public delegate void CheckReadEventHandler(object source, EventArgs args);
// Define an event based on that delegate
public event CheckReadEventHandler CheckRead;
// Raise an event
protected virtual void OnChecRead()
{
CheckRead?.Invoke(this, EventArgs.Empty);
}
private async Task OpenComm()
{
try
{
busyFlag = true;
//_cParam = _pdb.getParameters();
string selectedPortId = null;
string aqs = SerialDevice.GetDeviceSelector();
DeviceInformation = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);
foreach (var devInfo in DeviceInformation)
{
if (devInfo.Name == "USB-RS485 Cable")
{
selectedPortId = devInfo.Id;
}
}
if (selectedPortId != null)
{
SerialPort = await SerialDevice.FromIdAsync(selectedPortId);
if (SerialPort != null)
{
SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1500);
SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.BaudRate = 9600;
SerialPort.Parity = SerialParity.None;
SerialPort.StopBits = SerialStopBitCount.One;
SerialPort.DataBits = 8;
FlagComm = true;
}
else
{
var status = DeviceAccessInformation.CreateFromId(selectedPortId).CurrentStatus;
FlagComm = false;
_eldb.attachEvent("E1002", "Starting Comunication Failed: " + status);
//ContentDialog noSerialDevice = new ContentDialog()
//{
// Title = "No Serial Connection",
// Content = "Check connection and try again. App Closing.",
//};
//await noSerialDevice.ShowAsync();
//this.Dispose();
}
InitTool();
await ActivateListen();
busyFlag = false;
}
}
catch (Exception ex)
{
_eldb.attachEvent("E1cC", ex.Message);
}
}
private async Task Listen()
{
try
{
if (SerialPort != null)
{
busyFlag = true;
_dataReaderObject = new DataReader(SerialPort.InputStream);
await ReadAsync(_readCancellationTokenSource.Token);
busyFlag = false;
}
}
catch (Exception ex)
{
}
}
//using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000)))
//{
// await dataReaderObject.LoadAsync(1024).AsTask(cts.Token);
//}
private async Task ReadAsync(CancellationToken cancellationToken)
{
busyFlag = true;
const uint readBufferLength = 1024; // only when this buffer would be full next code would be executed
var loadAsyncTask = _dataReaderObject.LoadAsync(readBufferLength).AsTask(cancellationToken); // Create a task object
_dataReaderObject.InputStreamOptions = InputStreamOptions.ReadAhead;
var bytesRead = await loadAsyncTask; // Launch the task and wait until buffer would be full
if (bytesRead > 0)
{
InBuffer += _dataReaderObject.ReadString(bytesRead);
OnChecRead();
}
busyFlag = false;
}
private async void WriteComm(string str2Send)
{
using (var dataWriter = new DataWriter(SerialPort.OutputStream))
{
dataWriter.WriteString(str2Send);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
}
private async Task ActivateListen()
{
while (FlagComm)
{
await Listen();
}
}
private void dispatcherTimer_Tick(object sender, object e)
{
_eldb.attachEvent("SYSTEM", "Checking ADDR: " + num);
SendComm(num++, 5);
if (num == 5)
{
mTimer.Stop();
_eldb.attachEvent("SYSTEM", "Modules Checking Finished.");
busyFlag = false;
}
}
public void InitTool()
{
busyFlag = true;
_eldb.attachEvent("SYSTEM", "Setting Parameters.");
// Get Parameters
if (_pdb.GetParameters() == null)
{
// Set Default Parameters
_cParam.SetParam();
// Insert Default parameters in database
_pdb.Insert(_cParam);
// Update Parameters Object
_cParam = _pdb.GetParameters();
}
else
{
// Update Parameters Object
_cParam = _pdb.GetParameters();
}
// Check Addresses in Line
_eldb.attachEvent("SYSTEM", "Start Verifiyng.");
num = 0;
mTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(4000) };
mTimer.Tick += dispatcherTimer_Tick;
mTimer.Start();
}
public async void StartSerialComm()
{
try
{
await OpenComm();
}
catch (Exception ex)
{
_eldb.attachEvent("E7cC", ex.Message);
}
}
public void SendComm(params int[] list)
{
try
{
_cParam = _pdb.GetParameters();
string toSend = "";// = "A" + list[0] + "#";
switch (list[1])
{
case 0:
// Send Initialazation command
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
case 1:
// List of parameters (minPower, maxPower, ramPercent, initSpeed)
toSend = "##" + list[0] + "#" + list[1] + "#" + _cParam.minPower + "#" +
_cParam.maxPower + "#" + _cParam.percRamp + "#" + _cParam.initSpeed + "##";
break;
case 2:
// Send Status Request
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
case 3:
// Send a move Request
toSend = "##" + list[0] + "#" + list[1] + "#" + list[2] + "##";
break;
case 4:
// Send a Error Request
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
case 5:
// Send a start check
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
default:
_eldb.attachEvent("E1004", "Wrong Function Command.");
break;
}
if (toSend != "")
{
WriteComm(toSend);
}
else
{
_eldb.attachEvent("E1003", "Wrong String comunication.");
}
}
catch (Exception ex)
{
_eldb.attachEvent("E8cC", ex.Message);
}
}
public void Dispose()
{
try
{
if (SerialPort == null) return;
FlagComm = false;
SerialPort.Dispose();
SerialPort = null;
if (_dataReaderObject == null) return;
_readCancellationTokenSource.Cancel();
_readCancellationTokenSource.Dispose();
}
catch (Exception ex)
{
_eldb.attachEvent("E6cC", ex.Message);
}
}
}
Main Page:
public sealed partial class MainPage : Page
{
CComm _cC = new CComm();
EventLogDB _eldb = new EventLogDB();
procTrama _cProcTrama = new procTrama();
private DispatcherTimer mTimer;
public MainPage()
{
try
{
InitializeComponent();
// Get the application view title bar
ApplicationViewTitleBar appTitleBar = ApplicationView.GetForCurrentView().TitleBar;
// Make the title bar transparent
appTitleBar.BackgroundColor = Colors.Transparent;
// Get the core appication view title bar
CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
/*
ExtendViewIntoTitleBar
Gets or sets a value that specifies whether this title
bar should replace the default window title bar.
*/
// Extend the core application view into title bar
coreTitleBar.ExtendViewIntoTitleBar = true;
mTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(5000) };
mTimer.Tick += dispatcherTimer_Tick;
mTimer.Start();
_eldb.attachEvent("S1027", "Init Started...");
// Start comunication
_cC.StartSerialComm();
// Reference for CheckRead Event
_cC.CheckRead += OnCheckRead;
}
catch (Exception ex)
{
_eldb.attachEvent("MainP", ex.Message);
}
}
private void dispatcherTimer_Tick(object sender, object e)
{
if (!_cC.busyFlag)
{
Frame.Navigate(typeof(InitPage), null);
mTimer.Stop();
}
}
public void OnCheckRead(object source, EventArgs e)
{
try
{
if (CComm.InBuffer == null) return;
_cProcTrama.ProcessTrama(CComm.InBuffer);
CComm.InBuffer = "";
}
catch (Exception ex)
{
_eldb.attachEvent("OnCheckRead: ", ex.Message);
}
}
}
INIT Page:
public partial class InitPage : Page
{
CComm _cC = new CComm();
EventLogDB _eldb = new EventLogDB();
procTrama _cProcTrama = new procTrama();
public InitPage()
{
this.InitializeComponent();
_eldb.attachEvent("S1000", "System Started.");
// Reference for CheckRead Event
_cC.CheckRead += OnCheckRead;
}
private void button_Click(object sender, RoutedEventArgs e)
{
_eldb.attachEvent("S1001", "Login Activated.");
Frame.Navigate(typeof(Page1), null);
}
public void OnCheckRead(object source, EventArgs e)
{
if (CComm.InBuffer == null) return;
_eldb.attachEvent("OnCheckRead: ", CComm.InBuffer);
_cProcTrama.ProcessTrama(CComm.InBuffer);
}
}
Login Page where i more frequently the error occur:
public sealed partial class Page1 : Page
{
private CComm _cC = new CComm();
private procTrama _cProcTrama = new procTrama();
EventLogDB _eldb = new EventLogDB();
public Page1()
{
this.InitializeComponent();
// Reference for CheckRead Event
_cC.CheckRead += OnCheckRead;
user = null;
pass = null;
user_pass = 0;
}
private const int userLimit = 5;
private const int passLimit = 5;
private const char passChar = '*';
public string user
{
get; set;
}
public string pass
{
get; set;
}
public int user_pass
{
get; set;
}
private void execute(char val)
{
string aux = null;
if (user_pass == 1)
{
if (user == null)
user = val.ToString();
else
{
if (user.Length <= userLimit)
user = user + val;
}
userBtn.Content = user;
}
else
{
if (user_pass == 2)
{
if (pass == null)
pass = val.ToString();
else
{
if (pass.Length <= passLimit)
pass = pass + val;
}
for (int i = 0; i < pass.Length; i++)
aux = aux + passChar;
passBtn.Content = aux;
}
}
}
private void key1Btn_Click(object sender, RoutedEventArgs e)
{
execute('1');
}
private void key2Btn_Click(object sender, RoutedEventArgs e)
{
execute('2');
}
private void key3Btn_Click(object sender, RoutedEventArgs e)
{
execute('3');
}
private void key4Btn_Click(object sender, RoutedEventArgs e)
{
execute('4');
}
private void key5Btn_Click(object sender, RoutedEventArgs e)
{
execute('5');
}
private void key6Btn_Click(object sender, RoutedEventArgs e)
{
execute('6');
}
private void key7Btn_Click(object sender, RoutedEventArgs e)
{
execute('7');
}
private void key8Btn_Click(object sender, RoutedEventArgs e)
{
execute('8');
}
private void key9Btn_Click(object sender, RoutedEventArgs e)
{
execute('9');
}
private void key0Btn_Click(object sender, RoutedEventArgs e)
{
execute('0');
}
private void keyEntrarBtn_Click(object sender, RoutedEventArgs e)
{
if (pass == "123" && user == "123")
{
_eldb.attachEvent("S1002", "User Login: " + user);
Frame.Navigate(typeof(Page2), null);
}
user_pass = 0;
passBtn.Content = "Insirir Código";
userBtn.Content = "Inserir Utilizador";
}
private void keyApagarBtn_Click(object sender, RoutedEventArgs e)
{
pass = null;
user = null;
user_pass = 0;
passBtn.Content = "Inserir Código";
userBtn.Content = "Inserir Utilizador";
_eldb.attachEvent("S1003", " User data cleared.");
}
private void userBtn_Click(object sender, RoutedEventArgs e)
{
user_pass = 1;
userBtn.Content = "";
_eldb.attachEvent("S1004", "User button clicked.");
}
private void passBtn_Click(object sender, RoutedEventArgs e)
{
user_pass = 2;
passBtn.Content = "";
_eldb.attachEvent("S1005", "Pass button clicked.");
}
private void exitBtn_Click(object sender, RoutedEventArgs e)
{
_eldb.attachEvent("S1006", "Page1 exit button clicked.");
Frame.Navigate(typeof(InitPage), null);
}
public void OnCheckRead(object source, EventArgs e)
{
try
{
if (CComm.InBuffer == null) return;
_eldb.attachEvent("OnCheckRead: ", CComm.InBuffer);
_cProcTrama.ProcessTrama(CComm.InBuffer);
}
catch (Exception ex)
{
_eldb.attachEvent("OnCheckRead: ", ex.Message);
}
}
}