Handle a message I just sent with ActiveMQ and C# - c#

I'm a beginner at using ActiveMQ with C#. I've created a simple windows form with one button and one label. When I click on the button, i send a message to the queue and the label is initialized with the message I just sent. Of course, I could initialize my label directly but I want my form to rather consume the message from the queue in order to update my label.
The problem is I don't manage to handle the message in the same form to update my label. My consumer code is not called at all and yet, its initialized in the Load event of my form.
Here's the code
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
InitializeHandlerAMQ();
}
private void InitializeHandlerAMQ()
{
Tchat tchat = null;
IDestination dest = _session.GetQueue(QUEUE_DESTINATION);
using(IMessageConsumer consumer = _session.CreateConsumer(dest))
{
IMessage message;
while((message = consumer.Receive(TimeSpan.FromMilliseconds(2000))) != null)
{
var objectMessage = message as IObjectMessage;
if(objectMessage != null)
{
tchat = objectMessage.Body as Tchat;
if (tchat != null)
{
textBox2.Text += string.Format("{0}{1}", tchat.Message, Environment.NewLine);
}
}
}
}
}
If I close my windows form and restart it, then my label is well updated but I don't want to close it and re open it.
Do you have any ideas guys ?

Try creating a class with an event delegate like this.
A subscriber class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Apache.NMS;
using Apache.NMS.ActiveMQ;
using Apache.NMS.ActiveMQ.Commands;
namespace Utilities
{
public delegate void QMessageReceivedDelegate(string message);
public class MyQueueSubscriber : IDisposable
{
private readonly string topicName = null;
private readonly IConnectionFactory connectionFactory;
private readonly IConnection connection;
private readonly ISession session;
private readonly IMessageConsumer consumer;
private bool isDisposed = false;
public event QMessageReceivedDelegate OnMessageReceived;
public MyQueueSubscriber(string queueName, string brokerUri, string clientId)
{
this.topicName = queueName;
this.connectionFactory = new ConnectionFactory(brokerUri);
this.connection = this.connectionFactory.CreateConnection();
this.connection.ClientId = clientId;
this.connection.Start();
this.session = connection.CreateSession();
ActiveMQQueue topic = new ActiveMQQueue(queueName);
//this.consumer = this.session.CreateDurableConsumer(topic, consumerId, "2 > 1", false);
this.consumer = this.session.CreateConsumer(topic, "2 > 1");
this.consumer.Listener += new MessageListener(OnMessage);
}
public void OnMessage(IMessage message)
{
ITextMessage textMessage = message as ITextMessage;
if (this.OnMessageReceived != null)
{
this.OnMessageReceived(textMessage.Text);
}
}
#region IDisposable Members
public void Dispose()
{
if (!this.isDisposed)
{
this.consumer.Dispose();
this.session.Dispose();
this.connection.Dispose();
this.isDisposed = true;
}
}
#endregion
}
}
Winforms
In your windows form Subscribe to the queue like this
MyQueueSubscriber QueueSubscriber = new MyQueueSubscriber(QueueName, ActiveMQHost, QueueClientId);
QueueSubscriber.OnMessageReceived += new QMessageReceivedDelegate(QueueSubscriber_OnMessageReceived);
static void QueueSubscriber_OnMessageReceived(string message)
{
SetText(message);
}
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.labelname.value = text;
}
}
Resources:
Unfortunately there are not that many resources to teach C# & ActiveMQ. Try using http://activemq.apache.org/nms/ as this was quite good.
Try looking at a small article from http://www.codersource.net/MicrosoftNet/CAdvanced/PublishSubscribeinCusingActiveMQ.aspx. Disclaimer: This is my website and the article was written by me. Sorry for the self publicity. But I feel this is relevant to the topic.

Related

send generated value from class to textbox

I have a library that generates strings to a function called MessageOut. This function, i cannot change the structure of.
It looks like this:
public void MessageOut(string msg) //params or return-type cannot be changed
{
Console.WriteLine(msg);
}
I have a textbox in my form that i want to show this message in.
How would I go about appending msg to that textbox?
I've tried:
public void MessageOut(string msg) //params or return-type cannot be changed
{
Console.WriteLine(msg);
sendMessageTextBox(msg);
}
public string[] sendMessageTextBox(params string[] msg)
{
string send = "";
foreach(var i in msg){send = i;}
return send;
}
Form:
private void getWaveformBtn_Click(object sender, EventArgs e)
{
MyClass className = new MyClass();
foreach(var i in className.sendMessageTextBox())
{
errorTextBox.Text += i;
}
}
For obvious reasons, this doesn't work ,but i'm unsure how to go about doing this. (i've tried: how to send text to textbox through a different class?
Sending information to a textbox from a class to a form)
However, i cannot seem to get those solutions to work.
Any help is much appreciated.
TL;DR - i basically want to show the new strings that messageOut recieves in a textbox
This can be done in may different ways, one of them will be to use a queue, fill it from MessageOut and drain it on button press.
public class MessageHandler /* , MessageOutInterface */
{
private readonly Queue<string> messages;
public MessageHandler()
{
this.messages = new Queue<string>();
}
public void MessageOut(string message)
{
this.messages.Enqueue(message);
}
public IEnumerable<string> PendingMessages()
{
string message;
while (this.messages.Count > 0)
yield return this.messages.Dequeue();
}
}
Your UI code
private void getWaveformBtn_Click(object sender, EventArgs e)
{
foreach(var i in messageHandler.PendingMessages())
{
errorTextBox.Text += i;
}
}
If MessageOut is called on one thread (i.e. not the main thread) and the button press obviously happens on the main thread you'll need a thread safe approach:
public class MessageHandler /* , MessageOutInterface */
{
private readonly object syncRoot = new Object();
private readonly Queue<string> messages;
public MessageHandler()
{
this.messages = new Queue<string>();
}
public void MessageOut(string message)
{
lock (this.syncRoot)
{
this.messages.Enqueue(message);
}
}
public IEnumerable<string> PendingMessages()
{
lock (this.syncRoot)
{
var pending = this.messages.ToArray();
this.messages.Clear();
return pending;
}
}
}
This is not the best way to synchronize the threads but you can ask another question about synchronization.

event - object referance is not set to an instanse of an object windows forms C#

I am trying to raise an event in a DLL file refrenced to a windows forms project.
I have the following message when I run the program "Object is not set to an instace of an object":
namespace Server
{
public delegate void messageHnadler();
public class ClassServer
{
public event messageHnadler messageForChat
public string Message { get; set; }
public Socket listenerSocket;
public BinaryFormatter transBinary;
public Thread threadingServer;
public TcpListener listenerServer;
private List<TcpClient> connectedClients = new List<TcpClient>();
public bool OpenServer(string ipAddress, int PortNumber)
{
try
{
listenerServer = new TcpListener(IPAddress.Parse(ipAddress), PortNumber);//creating listener for clients to connect
listenerServer.Start();
threadingServer = new Thread(LoopThroughClients);
threadingServer.Start();
threadingServer = new Thread(GetMessage);
threadingServer.Start();
return true;
}
catch (Exception)
{
return false;
}
}
public void LoopThroughClients()
{
listenerSocket = listenerServer.AcceptSocket();
}
public void GetMessage()
{
while (true)
{
if (listenerSocket != null)
{
NetworkStream streamWithClient = new NetworkStream(listenerSocket);
transBinary = new BinaryFormatter();
string stringFromClient = (string)transBinary.Deserialize(streamWithClient);
if (stringFromClient != null)
{
Message = stringFromClient;
messageForChat();
}
streamWithClient = new NetworkStream(listenerSocket);
BinaryFormatter tranBinary = new BinaryFormatter();
tranBinary.Serialize(streamWithClient, stringFromClient);
stringFromClient = null;
}
}
}
In the windows forms project I signed the event to a function:
namespace Chat_Project_Server_UI
{
public partial class SeverUI : Form
{
OpenServerForm openServer = new OpenServerForm();
ClassServer serverForEvent = new ClassServer();
public SeverUI()
{
InitializeComponent();
openServer.ShowDialog();
serverForEvent.messageForChat += new messageHnadler(serverForEvent_messageForChat);
OpenningServer();
}
public void OpenningServer()
{
if(openServer.IsConnected)
{
ChatTextBox.AppendText("SERVER OPEN!\n");
}
else
{
ChatTextBox.AppendText("Faild to open server...\n");
}
}
private void test_Click(object sender, EventArgs e)
{
ChatTextBox.AppendText("aaaaa");
}
public void EventHolder()
{
}
void serverForEvent_messageForChat()
{
ChatTextBox.AppendText(serverForEvent.Message);
}
}
Always check if a handler has been assigned first as follows:
var handler = messageForChat;
if (handler != null)
handler()
Standard Way to handle Events inside the Class that defines it Is to Create A Method Named OnXxx and Always Check whether the Event is Assigned Handler Or Not
in your case define new function as following:
protected void OnMessageForChat(){
//protected modifier allows subclasses to raise the event by calling this method
if (messageForChat!=null)messageForChat();
}
And WhenEver you want to raise the event Just Call this Function

Correct Event handling in C#

this is basically a follow up to a previous question (Triggering an event in c# from c++ and declaring LPCWSTR). I've revised my code based on the answers and comments I have received and I solved the initial issue, which was passing the event to the GpioSetupInterruptPin from a gpio api. I don't have a lot of documentation on the api but what i'm trying to achieve is: have a form with a white label; after pressing a switch, the label turns yellow.
The problem i'm having now is the event seems to trigger as soon as it's created (the "execute" message is passed to the debug dialog and the label turns yellow) but it doesn't do anything when i toggle the switch. I was told in the last question to use WaitForSingleObject but i'm not really sure where to call it and this article only added to my confusion.
public partial class Form1 : Form
{
// P/Invoke CreateEvent and WaitForSingleObject
private void GPIO_Open() //get handle for gpio
private void GPIO_Output() //output pin declaration
private void button1_Click(object sender, EventArgs e)
{
Interrupt_Setup();
}
private void Interrupt_Setup()
{
hGPIO = GPIOapi.GpioOpenHandle(); //returns a handle to the gpio
GIPO_ON = true;
Debug.WriteLine("Driver open \n" + hGPIO);
GPIO_Output(); //set output pins
GPIO_Interrupt(Trigger); //configure interrupt
}
private void GPIO_Interrupt(string trigger)
{
bool ok;
_Main();
//INTERRUPT DECALRATION
ok = GPIOapi.GpioSetupInterruptPin(hGPIO, port6, 4, GPIOapi.INT_TRIGGER_MODE.TRIGGER_MODE_EDGE,
GPIOapi.INT_TRIGGER_POLARITY.TRIGGER_POL_HIGH_RISING, trigger, true);
Thread waitThread=new Thread(WaitForTrigger);
waitThread.Start();
if (!ok)
Debug.WriteLine("NO interrupt");
else
Debug.WriteLine("Interrupt set for:" + port6 + "04" + " at " + hGPIO);
}
public static string Trigger = "InputProcessUpdateHandler";
public static IntPtr handle = CreateEvent(IntPtr.Zero, false, false, Trigger); //used P/Invoke
private static InputProcessor inputProcessor = null;
public Color[] color =
{
Color.Orchid, Color.DarkOrchid, Color.GreenYellow, Color.CornflowerBlue, Color.SteelBlue,Color.Crimson
};
public int i = 0;
public void WaitForTrigger()
{
while(true)
{try
{
if (WaitForSingleObject(handle, 0xFFFFFFFF) == false)
{
BeginInvoke(((System.Action)(() =>label2.BackColor = color[i])));
i++;
if (i > 4)
i = 0;
}
Thread.Sleep(300);
}
catch (Exception e)
{ Debug.WriteLine("exception: " + e); }}
}
}
private void _Main()
{
inputProcessor = new InputProcessor();
ShowToggle showToggle = new ShowToggle(inputProcessor);
inputProcessor.Process(label1);
}
public class ShowToggle
{
private InputProcessor _inputProcessor = null;
public ShowToggle(InputProcessor inputProcessor)
{
_inputProcessor = inputProcessor;
_inputProcessor.updateHandledBy += InputProcessUpdateHandler;
}
private void InputProcessUpdateHandler(Label label)
{
label.BackColor = Color.Yellow;
Debug.Write("execute");
}
}
public class InputProcessor
{
public delegate void InputProcessUpdateHandler(Label label);
public event InputProcessUpdateHandler updateHandledBy = null;
public void Process(Label label)
{
if (updateHandledBy != null)
updateHandledBy(label);
}
}
If anyone could help me with this, I would be very grateful.
*** I got it working but it looks a right mess. Could anyone help me straighten it out?
You code is really confusing to me. I think what you want is something like this. Bear in mind I'm typing this into the SO text editor, so don't expect it to compile and just work - it's a guide. Consider it a step above pseudocode.
public class DeviceInterrupt
{
IntPtr m_gpio;
string m_eventName;
public event EventHandler OnInterrupt;
public DeviceInterrupt(int port)
{
// get a driver handle
m_gpio = GPIO_Open();
// generate some unique event name
m_eventName = "GPIO_evt_" + port;
// wire up the interrupt
GpioSetupInterruptPin(m_gpio, port, m_eventName, ...);
// start a listener
new Thread(EventListenerProc)
{
IsBackground = true,
Name = "gpio listener"
}
.Start();
}
public void Dispose()
{
// TODO: release the handle
}
private void EventListenerProc()
{
// create the event with the name we sent to the driver
var wh = new WaitHandle(false, m_eventName);
while (true)
{
// wait for it to get set by the driver
if (wh.WaitOne(1000))
{
// we have an interrupt
OnInterrupt.Fire(this, EventArgs.Empty);
}
}
}
}
Usage would then be something like this:
var intr = new DeviceInterrupt(4);
intr.OnInterrupt += MyHandler;
....
void MyHandler(object sender, EventArgs a)
{
Debug.WriteLine("Interrupt occurred!");
}
Note
The Compact Framework doesn't support actual named system events, so the named WaitHandle I use in my code above is not a CF-supplied WaitHandle. Instead I'm using the one from the Smart Device Framework. You could also P/Invoke to CreateEvent and WaitForSingleObject yourself.

Handling events after receiving a MSMQ message (thread issue?)

I created two separate Windows Forms applications in C# that use MSMQ for communicating. Here's how it works, it looked simple enough though:
App1 sends a details request to App2.
App2 creates an event to open the window.
App2 opens a "details" window.
The only problem I have is that when received the message, the "details" window freezes after appearing.
As I handle MSMQ messages handling in an object that uses threads, I suspect the problem comes from there... But I have no experience in handling MSMQ messages or specific events handling between parts of an application.
Here's part of the code I use for App2:
/*Class declared in the Core namespace*/
public class TaskMessageQueueHandler
{
public TaskMessageQueueHandler()
{
this.Start();
}
private Thread m_thread;
private ManualResetEvent m_signal;
public event System.EventHandler messageReceived;
public void Start()
{
m_signal = new ManualResetEvent(false);
m_thread = new Thread(MSMQReceiveLoop);
m_thread.Start();
}
public void Stop()
{
m_signal.Set();
}
protected virtual void SendEvent(object sender, EventArgs e)
{
if (messageReceived != null)
messageReceived(this.message, e);
}
public string message;
private void MSMQReceiveLoop()
{
bool running = true;
MessageQueue queue = new MessageQueue(#".\Private$\queue1");
while (running)
{
try
{
var message = queue.Receive();
message.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
this.message = message.Body.ToString();
string m = this.message;
SendEvent(m, System.EventArgs.Empty);
if (m_signal.WaitOne(10))
{
running = false;
}
}
catch
{
Console.WriteLine("ERROR");
running = false;
}
}
}
}
/*Main process, in the Program namespace*/
[...]
Core.TaskMessageQueueHandler tmqh = new Core.TaskMessageQueueHandler();
EventListener el = new EventListener();
tmqh.messageReceived += new System.EventHandler(el.ShowDetails);
[...]
/* Class in the Program namespace */
class EventListener
{
public void ShowDetails(object sender, EventArgs e)
{
int numero = int.Parse(sender as string);
Details details = new Details(numero);
details.Show();
}
}
Where did I go wrong? Where did I go right?
Thanks a lot,
Stephane.P
EDIT: if the MSMQ handler is stopped with Stop() anywhere around the event sending, the details window appears then disappears right away...
EDIT2: After the workaround given by Slugart, I managed to make this work:
class EventListener
{
Main control;
public EventListener(Main main)
{
control = main;
}
public void ShowDetails(object sender, EventArgs e)
{
int numero = int.Parse(sender as string);
control.Invoke((Action)(() => ShowDetails(numero)));
}
private void ShowDetails(int numero)
{
Details details = new Details(numero);
details.Show();
}
}
Which is used like:
Core.TaskMessageQueueHandler tmqh = new Core.TaskMessageQueueHandler();
EventListener el = new EventListener(this);
tmqh.messageReceived += new System.EventHandler(el.ShowDetails);
You're creating and displaying a form Details on a thread other than the main GUI thread and not an STA thread at that.
Your EventListener should have a reference to a running form (your main form perhaps) and then call form.Invoke() on it.
class EventListener
{
Control control; // A valid running winforms control/form created on an STA thread.
public void ShowDetails(object sender, string message)
{
int numero = int.Parse(message);
control.Invoke(() => ShowDetails(numero))
}
private void ShowDetails(int numero)
{
Details details = new Details(numero);
details.Show();
}
}
Also sending your event data as the sender is not really following the Event pattern that has been put in front of you. You want to use the EventArgs parameter for this, use the EventHandler delegate (EventHandler in your case).

update a richtextbox from a static class

I have the following code:
namespace SSS.RemoteTruckService
{
public partial class Startup : Form
{
private Timer _gpsTimer;
private Timer _ppsTimer;
private Timer _creditCardTimer;
private Timer _iniTimer;
public string Message
{
get { return richTextBox_Message.Text; }
set
{
richTextBox_Message.Invoke((MethodInvoker)(()
=> richTextBox_Message.Text = DateTime.Now + " " +
value + Environment.NewLine + richTextBox_Message.Text));
}
}
public Startup()
{
InitializeComponent();
}
private void ButtonStartClick(object sender, EventArgs e)
{
StartRemoteTruck();
}
private void ButtonPauseClick(object sender, EventArgs e)
{
if (_gpsTimer.Enabled) _gpsTimer.Enabled = false;
if (_ppsTimer.Enabled) _ppsTimer.Enabled = false;
if (_creditCardTimer.Enabled) _creditCardTimer.Enabled = false;
if (_iniTimer.Enabled) _iniTimer.Enabled = false;
ProcessIniFile.StopProcess();
}
public void StartRemoteTruck()
{
Message = "RemoteTruck started.";
if (Settings.GlobalSettings == null)
{
Message = "GlobalSettings was null or not loaded. Cannot continue.";
Logging.Log("GlobalSettings was null or not loaded. Cannot continue.", "RemoteTruck", Apps.RemoteTruckService);
Environment.Exit(0);
}
if (Settings.GlobalSettings.IniFileWatcherEnabled)
{
ProcessIniFile.StartProcess();
}
CreateTimers();
}
And in the ProcessIniFile.StartProcess() I have the code:
namespace SSS.RemoteTruckService.inifile
{
public static class ProcessIniFile
{
private static DateTime _iniLastWriteTime;
private static readonly string Inifile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "sss.ini");
private static FileSystemWatcher _watcher;
public static void StartProcess()
{
ReadIniFile();
SaveCurrentIniReadings();
CreateIniFileWatcher();
}
public static void StopProcess()
{
if (_watcher != null)
{
_watcher.EnableRaisingEvents = false;
_watcher = null;
}
}
private static void CreateIniFileWatcher()
{
_watcher = new FileSystemWatcher
{
Path = Environment.GetFolderPath(Environment.SpecialFolder.Windows),
NotifyFilter = NotifyFilters.LastWrite,
Filter = "sss.ini"
};
_watcher.Changed += SssIniWatcherChanged;
_watcher.EnableRaisingEvents = true;
}
I'd like to pass back the the calling form the status of the reads of the file watcher.
Maybe I'm overthinking this, but if I want to add to the Message on the main form, how do I get to it?
You can use Events for that. Your process can send events and your form can handle them.
More info: http://msdn.microsoft.com/en-us/library/awbftdfh.aspx
The simple but not pretty way I like to use is to make that part of the form static as well. For example, creating a static variable WriteMessage, and in your Form Load or Startup(), you can set it:
WriteMessage = (s) => Message = s;
Sure this has some issues, but it's a quick way to get it done. One of those issues is that, you may need to use Dispatcher.invoke if you're not on the UI thread.

Categories

Resources