Please can you help me with advice or demo code for the following task:
I had a program in WPF which constantly listen on a serial port, If it received a specific signal it should change a property in a ViewModel. The listener is start on another thread so I had wonder how can I change a ViewModel property from another thread, I try to pass a property by reference but that was not possible.
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//My property in the view model
private Boolean _Lock;
public Boolean Lock
{
get { return _Lock; }
set
{
_Lock = value;
OnPropertyChanged("Lock");
}
}
//Start the listener thread
Thread ComListenThread = new Thread(delegate()
{
Com cm = new Com(Path,Lock);
cm.Start();
});
ComListenThread.Start();
class Com
{
private Uri web { get; set; }
private Boolean Lock { get; set; }
public Com(Uri Path,Boolean _Lock)
{
web = Path;
Lock = _Lock;
}
public void Start()
{
try
{
port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
}
catch (Exception e)
{
MessageBox.Show("Reason {0}:", e.Message);
}
port.ReadTimeout = 500;
port.Open();
int position = 0;
while (true)
{
try
{
int len = port.Read(data, position, data.Length - position);
position += len;
}
catch (TimeoutException)
{
//How to change Lock property
Lock = (data[2]==5)?true:false;
position = 0;
}
}
}
}
So my question is how can I pass the property which will be changed on another thread in constant loop.
By passing the parent object you should have access to the property to change it; however, you may want to switch back to the UI thread (Dispatcher.Invoke) before doing this, as cross-threaded mutation of "observer" models rarely ends well.
Another approach is for your code to simply raise an event (nothing to do with this property), and have your UI code switch to the UI tread and update the view-model. This approach separates the UI code cleanly from the "doing" code (since the "doing" code knows nothing of the view-model or threading), and is particularly useful if you need to support arbitrary UI models.
Related
my question might seem a bit odd, but what would be the best approach to create a WPF Socket client using the MVVM pattern.
Right now on my ViewModel, i create a thread, which attempts to connect to the server in a while loop, and wait for connection, after it's connected it gets data from the server.
Is there a better way to make it so i won't have to use a new Thread while not blocking the main UI thread?
Relevant ViewModel code:
serverInfo.ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverInfo.PORT = 1488;
//Initialize LeecherList
p_LeecherList = new ObservableCollection<LeecherDetails>();
//Subscribe to CollectionChanged Event
p_LeecherList.CollectionChanged += OnLeecherListchanged;
AccountsInfo = JsonConvert.DeserializeObject<RootObject>(File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(), "Accounts.json")));
foreach (var x in AccountsInfo.Accounts)
{
p_LeecherList.Add(new LeecherDetails("N/A", x.Email, x.Password, false, "Collapsed"));
}
base.RaisePropertyChangedEvent("LeecherList");
Thread ConnectionLoop = new Thread(() =>
{
ServerStatus = "Connecting...";
while (true)
{
if (!serverInfo.HasConnectedOnce && !serverInfo.ClientSocket.Connected)
{
try
{
serverInfo.ClientSocket.Connect(IPAddress.Loopback, serverInfo.PORT);
}
catch (SocketException)
{
}
}
else if (serverInfo.ClientSocket.Connected && !serverInfo.HasConnectedOnce)
{
serverInfo.HasConnectedOnce = true;
ServerStatus = "Online";
break;
}
}
while (true)
{
try
{
var buffer = new byte[8000];
int received = serverInfo.ClientSocket.Receive(buffer, SocketFlags.None);
if (received == 0) return;
var data = new byte[received];
Array.Copy(buffer, data, received);
var st = helper.ByteToObject(data);
if (st is string info)
{
}
else
{
}
}
catch
{
continue;
}
}
});
ConnectionLoop.IsBackground = true;
ConnectionLoop.Start();
Thanks in advance.
Right now on my ViewModel, i create a thread, which attempts to connect to the server in a while loop, and wait for connection, after it's connected it gets data from the server.
Is there a better way to make it so I won't have to use a new Thread while not blocking the main UI thread?
Well; you should put this logic in a kind of Service.
Example:
So, you could create a service like this, note: the start, stop and the event to pass the data.
The basic idea is to move the more business like communication logic in a separate service, so that, if you need to change it later on, the logic is more isolated and not mixed with your viewmodel.
//note, you could encapsulate functionality in an interface, e.g.: IService
public class SomeService
{
public event EventHandler<YourEventData> OnSomethingHappening;
public SomeService(some parameters)
{
//some init procedure
}
public void Stop()
{
//your stop logic
}
public void Start()
{
//your start logic
}
private void Runner() //this might run on a seperate thread
{
while(running)
{
if (somecondition)
{
OnSomethingHappening?.Invoke(this, new YourEventData());
}
}
}
public string SomeFooPropertyToGetOrSetData {get;set;}
}
Create one of these somewhere in your application, perhaps at startup.
Then pass it to your viewmodel, maybe through the constructor. In that case your viewmodel will look something like this:
public class YourViewModel
{
private SomeService_service;
public YourViewModel(SomeServiceyourService)
{
_service = yourService;
_service.OnSomethingHappening += (s,a) =>
{
//event handling
};
}
}
//etc.
In our WPF application, we have classes that need to "raise" a notification that something has happened, and other classes that operate as listeners to that notification and have to execute some code as a response upon getting that notification. This is the common pattern of Publish/Subscribe.
Now, I will show you how it is done in our project. I think we use a bad practice of that pattern, and this causes our UI to freeze and not be responsive as expected.
The event args class:
public class IsDisconnectedAction : EventArgs
{
public override string ToString()
{
return GetType() + " Key: ";
}
public ElementType ElementKey { get; set; }
public static ActionTemplate<IsDisconnectedAction> MY_Action = new ActionTemplate<IsDisconnectedAction>();
}
Raising the Notification
IsDisconnectedAction.MY_Action.Raise(new IsDisconnectedAction() { ElementKey = _elementKey });
The implementation of the Raise method
public void Raise(T info)
{
if (_event == null) return;
InvokeIfNecessary.Invoke(() =>
{
_event (null, info);
});
}
private event EventHandler<T> _event;
public event EventHandler<T> Event
{
add
{
lock (_lock)
{
_event += value;
}
}
remove
{
lock (_lock)
{
_event -= value;
}
}
}
private readonly object _lock = new object();
The Invoke method of InvokeIfNecessary
public static void Invoke(Action action)
{
if (Application.Current == null)
{
action();
return;
}
if (Application.Current.Dispatcher.CheckAccess())
action();
else
{
Application.Current.Dispatcher.Invoke(action, DispatcherPriority.Send);
}
}
NOTE this code is executed on the UI thread, and I think it's not the correct approach.
Then, the listener:
It can be a class in the UI that indeed need to update something in the UI:
IsDisconnectedAction.MY_Action.Event += OnElementDisconnected;
private void OnElementDisconnected(object sender, IsDisconnectedAction e)
{
if (e == null) return;
_textBlock.Text = "Disconnected";
}
It can be a class that listens to the events in the same manner but does NOT even need to update anything in the UI (Here I think that raising the event and listening to it, can all be done outside of the UI thread).
Can you please suggest what is the best practice to achieve what I want?
Sometimes these events are raised so many times per second and all of that happens in the UI thread, and I think it might harm the responsiveness of the UI. Thank!
I need the following logic implemented:
a thread to which you can subscribe/unsubscribe methods at runtime.
It's fine for all these methods to have an header such as (Object sender, EventArgs e) and to return void.
These methods scope must be the scope of the class where they are defined lexically.
There's no guarantee about the order of execution
I've come up with the following implementation, which seems to do exactly what I need: basically I start an internal thread which triggers an event each x milliseconds. You can subscribe/unsubscribe delegates to this event through appropriate methods.
Before sticking to it I'd like to know if there may be subtle issues following this approach.
public class Orchestrator
{
private Thread _mainThread;
private event MethodDelegate _mainEvent;
public delegate void MethodDelegate (Object sender, EventArgs e);
private bool _stop = false;
private short _ms = 100;
public short PollingInterval { get { return _ms; }
set
{
_ms = value;
}
}
public Orchestrator()
{
_mainThread = new Thread(new ThreadStart(_execute));
}
public void Start()
{
_stop = false;
_mainThread.Start();
}
public void Stop()
{
_stop = true;
}
public void Clear()
{
_mainEvent = null;
}
public void Push(MethodDelegate method)
{
_mainEvent += method;
}
public void Pop(MethodDelegate method)
{
_mainEvent -= method;
}
private void _execute()
{
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
}
}
That's basically fine. You need to make _stop volatile. In C# the event accessor methods are thread-safe so that works fine.
The exception handling is very questionable. Do you really want to spam errors to the console? Define an event OnError and report errors to the consumer of your class.
You could use a timer or await Task.Delay to save a thread. This would make sense if there are a lot of such class instances at the same time. If there is just one this is likely not worth the effort.
You have a race condition which could cause a NullReferenceException, in:
while(!_stop)
{
if (_mainEvent != null)
try
{
_mainEvent(this, new EventArgs());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Thread.Sleep(_ms);
}
Some other thread could unsubscribe from the event or call Clear() inbetween if (_mainEvent != null) and the call of _mainEvent.
To avoid this, you should copy _mainEvent into a local variable and check that against null, and use that instead:
var mainEvent = _mainEvent;
if (mainEvent != null)
try
{
mainEvent(this, new EventArgs());
In any case, I think you should be using a Timer for this rather than rolling-your-own.
I am developing a application with C# and Arduino.I reading values from Arduino and set the value on the textbox.I want always read value from Arduino and set this on the interface.However this code doesn't working.
Shoul I run while statement in a different thread?
This is my code
SerialPort port = new SerialPort("COM4", 9600);
port.Open();
while (true)
{
String s=port.ReadLine();
txtValue.Text=s;
}
port.Close();
}
I want show value which I read from Arduino to show in the textbox simultaneously.
This is code to start (put it in constructor, window Loaded or button click event):
Task.Run(() =>
{
_stop = false; // define as private field of window class
var port = new SerialPort("COM4", 9600);
port.Open();
while (!_stop)
{
var s=port.ReadLine();
Dispatcher.Invoke(() => txtValue.Text = s); // InvokeAsync?
}
port.Close();
});
This is code to stop (put it into window Closing event):
_stop = true;
This doesn't uses any bindings, but should give you an idea of how to organize port operation (with or without bindings).
I can't speak to the arduino side, but if you are using .net 4.0 or 4.5 you could do something like below:
Task myTask = Task.Factory.StartNew(() => {
while (true)
{
String s=port.ReadLine();
txtValue.Text=s;
}
});
as mentioned by Sinatr be sure to have a way to stop execution. You could do this by setting a vairable instead of using "true". As for where to put the code it is really dependent on what your final program will be.
With MVVM Light and SolidSoils4Arduino you should be able to quickly create an observable binding with Arduino serial messages.
Here is a basic viewmodel class:
public class MainViewModel : GalaSoft.MvvmLight.ViewModelBase, IObserver<string>
{
#region Fields
private string _lastSerialMessageReceived;
private readonly ObservableCollection<string> _serialMessages = new ObservableCollection<string>();
#endregion
#region Constructors
public MainViewModel()
{
var connection = new Solid.Arduino.SerialConnection("COM3", Solid.Arduino.SerialBaudRate.Bps_115200);
var session = new Solid.Arduino.ArduinoSession(connection);
session.CreateReceivedStringMonitor().Subscribe(this);
}
#endregion
#region Public Interface
public void OnCompleted()
{
throw new NotImplementedException();
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnNext(string value)
{
_serialMessages.Add(value);
LastSerialMessageReceived = value;
}
public ObservableCollection<string> SerialMessages
{
get { return _serialMessages; }
}
public string LastSerialMessageReceived
{
get { return _lastSerialMessageReceived; }
private set { Set(() => LastSerialMessageReceived, ref _lastSerialMessageReceived, value); }
}
#endregion
}
You can bind your textbox to property LastSerialMessageReceived. Property SerialMessages could be bound to a listbox.
I am trying to create a thread which will continuously check for changes to a value, then visually show that change in a PictureBox located in my GUI.
What I actually wrote is a bit more complicated, so I simplified it while keeping the basic idea, I would be happy to provide clarification if this isn't enough:
public class CheckPictures
{
PictureBox update;
List<String> check;
public CheckPictures(PictureBox anUpdate, List<String> aCheck)
{
update = anUpdate;
check = aCheck;
}
public void start()
{
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
}
}
static int Main(string[] args)
{
List<String> picturesList = new List<String>();
CheckPictures thread1 = new CheckPictures(PictureBox1, picturesList);
Thread oThread1 = new Thread(thread1.start));
}
What I want it to do is dynamically change the picture in PictureBox1 if I were to add the string "Me" to pictureList. The above code isn't working like I'd hoped. I had thought that by passing the actual PictureBox and List, any changes to the List elsewhere is the program would be caught by the thread. So my first question is: Is this possible? And if so, what change would I need to make to my code to achieve it?
You might want to use events. You register an eventhandler and when something changes in one thread it calls an event handler in the other to do the work. Busy waiting wastes cpu.
You definetely do not want to do an infinite loop, this will just consume cpu:
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
I think you should look into the CountdownLatch class.
public class CountdownLatch
{
private int m_remain;
private EventWaitHandle m_event;
public CountdownLatch(int count)
{
m_remain = count;
m_event = new ManualResetEvent(false);
}
public void Signal()
{
// The last thread to signal also sets the event.
if (Interlocked.Decrement(ref m_remain) == 0)
m_event.Set();
}
public void Wait()
{
m_event.WaitOne();
}
}
The basic idea here is that you need to stop execution on your thread for some time and resume whenever a certain condition has been met (perhaps on another thread).
In other words, you will have a counter, decrement its value on certain condition and whenever it goes to zero you fire your event, execute some code and then start over (stop execution and wait for the counter to go to zero).
In your case you could set the counter to 1 and decrement its value whenever you've set aCheck[0] = "Me"; This way you don't waste CPU.
Pseudo code:
Initialize counter:
CountdownLatch latch = new CountdownLatch(1);
Make thread wait:
public void start()
{
while(true)
{
latch.Wait(); //execution stops
{
//execution resumes once the latch counter is zero.
if (aCheck[0] == "Me") //double check you have what you need
{
update.Image = Image.fromFile("");
latch = new CountdownLatch(1); //reset if you need to do it again
}
}
}
}
Whenever your condition is met (i.e. aCheck[0] = "Me";) signal your latch:
latch.Signal();
this last line will make the thread resume execution. Good stuff.
Create some object, which will raise event, when new picture was added. E.g. class representing pictures collection:
public class PicturesCollection
{
public event EventHandler<PictureAddedEventArgs> PictureAdded;
private List<string> _pictures = new List<string>();
public void Add(string name)
{
_pictures.Add(name);
if (PictureAdded != null)
PictureAdded(this, new PictureAddedEventArgs(name));
}
public IEnumerable<string> Pictures
{
get { return _pictures; }
}
}
If you want to provide some additional data to event, create custom EventArgs:
public class PictureAddedEventArgs : EventArgs
{
public PictureAddedEventArgs(string name)
{
Name = name;
}
public string Name { get; private set; }
}
All you need now - create pictures collection and subscribe to that event:
static int Main(string[] args)
{
PicturesCollection pictures = new PicturesCollection();
pictures.PictureAdded += Pictures_PictureAdded;
}
static void Pictures_PictureAdded(object sender, PictureAddedEventArgs e)
{
if (e.Name == "Me")
PictureBox1.Image = Image.fromFile("");
}
If you add somewhere in your application new picture to collection, it will raise PictureAdded event, which you can handle and update PictureBox. CPU is not wasted in this case.