Process items one by one when use websocket and BackgroundWorker C# - c#

I have WPF program which listens what income data from Pushbullet through websocket (onMessage event)
The process of data is done in a background worker (in DoWork event) in order to not freeze the UI.
But might happen the data are more than one and seems that results are broken.
WS.onMessage += (s, ev) => {
var wk = new BackgroundWorker();
wk.DoWork += (se, evt) => {
Process1();
Dispatcher.Invoke(()=>{ print to ui });
}
wk.RunWorkerAsync();
}
How to process item one by one when onMessage is triggered? I mean I want to process an item and the process another after first is done even onMessage is already triggered few times, depends how many data comes ...

I'd suggest looking at Microsoft's Reactive Framework (NuGet "System.Reactive"). Then you can do this:
IDisposable subscription =
Observable
.FromEventPattern<EventHandler, EventArgs>(
h => WS.onMessage += h, h => WS.onMessage -= h)
.SelectMany(ep => Observable.Start(() => Process1()))
.ObserveOnDispatcher()
.Subscribe(x =>
{
/* Print to UI */
});
It'll process on a background thread and then marshall back to the dispatcher. It'll produce zero or more values in the .Subscribe method and will only produce one value at a time.
If you want to close down the observable just call .Dispose() on the subscription.
You might need to adjust the EventHandler & EventArgs types to suit your source event.

Related

Dispatcher.Invoke to update WPF canvas causes performance problems

I am using Websockets to draw data on my canvas:
webSocket.OnMessage += (sender, e) =>
{
String websocketData = e.Data.Substring(3);
WebSocketDataStructure jsonData = JsonConvert.DeserializeObject<WebSocketDataStructure>(websocketData);
// Give control back to main thread for drawing
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => this.updateCanvas(jsonData)));
};
private void updateCanvas(WebSocketDataStructure myData)
{
CanvasUtils.DrawLine(MyCanvas, colorNormalBrush, myData.hsLine.x1, myData.hsLine.y1, myData.hsLine.x2, myData.hsLine.y2);
}
When I get multiple messages per second the application starts to lag. I read that using Dispatcher.BeginInvoke() is bad for handling frequent data, since we immediately switch back to the UI-Thread every time.
Is there a better way to implement this? I thought about creating a timer and updating the UI-Thread every full second. This would work by storing websocket data in a List, and process it on the UI-Thread (https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem). My only problem with this approach was, that I couldn't set up an endless loop with Thread.Sleep(1000) on the UI-Thread.
You could queue your high-frequent data and read items from the data queue at a lower pace. By using a DispatcherTimer you could avoid the need for directly calling the Dispatcher.
var queue = new ConcurrentQueue<WebSocketDataStructure>();
webSocket.OnMessage += (s, e) =>
{
var websocketData = e.Data.Substring(3);
var jsonData = JsonConvert.DeserializeObject<WebSocketDataStructure>(websocketData);
queue.Enqueue(jsonData);
};
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
timer.Tick += (s, e) =>
{
WebSocketDataStructure data;
while (queue.TryDequeue(out data))
{
CanvasUtils.DrawLine(MyCanvas, colorNormalBrush,
data.hsLine.x1, data.hsLine.y1, data.hsLine.x2, data.hsLine.y2);
}
};
timer.Start();

A Better Way to Implement a WaitForMouseUp() Function?

I needed a small function that will wait for the left mous button to be released, and will not be based on the MouseUp event.
In many cases when we need this, we simply write an event handler for the MouseUp event.
It's simple, and it works.
There are however cases, where using the MouseUp event will not be useful,
such as when we are already in another (different) event handler,
and the left mouse button might be pressed when this event handler is called, and we need to wait for it to be released.
(the goal is to have a single flow of code, and not have to split it between several places which might already be occupied with another code)
I implemented it this way:
public void WaitForMouseUp()
{
while( (Control.MouseButtons&MouseButtons.Left)!=0 )
Application.DoEvents();
}
It works,
you can use it for example when you are in the event handler for the Control.Enter event,
and if the control was entered via the mouse, then this function will block until the mouse button is released.
I only worry about one thing:
I am using Application.DoEvents() there, and I wonder if there another way instead of using Application.DoEvents().
(Application.DoEvents(); has disadvantages of possible reentrancy, and so, so for this reason I try to minimize using it, whenever possible)
Anyone has an idea with what I can substitute the Application.DoEvents() part?
Here's an awesome way to do what you're asking. Use Microsoft's Reactive Extensions to make a single line of code do everything you want.
The reactive extensions provide a whole lot of operators that can be applied to events.
So first some basic observables that directly relate to normal control events:
var mouseEnters =
Observable
.FromEventPattern(
h => button1.MouseEnter += h,
h => button1.MouseEnter -= h);
var mouseLeaves =
Observable
.FromEventPattern(
h => button1.MouseLeave += h,
h => button1.MouseLeave -= h);
var mouseUps =
Observable
.FromEventPattern<MouseEventHandler, MouseEventArgs>(
h => button1.MouseUp += h,
h => button1.MouseUp -= h);
Now we need a query that will fire only once when the mouse up occurs, but only if the mouse has entered the button1, but only before it leaves.
var query =
mouseEnters
.Select(me => mouseUps.Take(1).TakeUntil(mouseLeaves))
.Switch();
Now to subscribe to the event to be able to handle it:
var subscription =
query
.Subscribe(ep =>
{
/*
this code runs for the first mouse up only
after each mouse enter on `button1`
unless the mouse leaves `button1`
*/
});
It now because very simple to unsubscribe as the type of subscription is IDisposable. So you simply call subscription.Dispose();.
Just NuGet "Rx-WinForms" to get the bits for your project.
In fact what #Kai Brummund is suggesting is a variation of my answer to Force loop to wait for an event. Adjusting the code from there for MouseUp is simple as
public static class Utils
{
public static Task WhenMouseUp(this Control control)
{
var tcs = new TaskCompletionSource<object>();
MouseEventHandler onMouseUp = null;
onMouseUp = (sender, e) =>
{
control.MouseUp -= onMouseUp;
tcs.TrySetResult(null);
};
control.MouseUp += onMouseUp;
return tcs.Task;
}
}
and the usage is
Control c = ...;
await c.WhenMouseUp();
The same technique can be used for any event.
If You wan't to write a flow within a single method, you can make an awaitable using a TaskCompletionSource.
Your flow:
await MouseUp();
...
private Task MouseUp() {
_tcs = new TaskCompletionSource();
return _tcs.Task;
}
public ... OnMouseUpEvent() {
_tcs?.SetResult(true);
}
Sorry for Pseudo code, will update this once I get something other than a mobile.
OT: Commenters: Think outside of the Box!
I needed a small function that will wait for the mouse's left button to be released.
No you don't. WinForms GUI programming is event driven, asynchronous. You should use the MouseUp event to detect the mouse button's release. This does mean that you need to implement your logic using state based asynchronous techniques, rather than the synchronous model that you crave.

Publishing last recieved data when Observable is Subscribed

I have created GeoCoordinateReactiveService using Rx in Windows Phone 8.
The problem is that I need to start Geocoordinatewatcher before I Subscribe for Observable which is observing over PositionChange event.
So if position change event is fired before I subscribe for the first time I won't be getting the last data. How can I change current implementation to do so.
below is my current code:
this.StatusObservable = Observable
.FromEventPattern<GeoPositionStatusChangedEventArgs>(
handler => geoCoordinateWatcher.StatusChanged += handler,
handler => geoCoordinateWatcher.StatusChanged -= handler)
.Select(ep => ep.EventArgs.Status);
this.PositionObservable = Observable
.FromEventPattern<GeoPositionChangedEventArgs<GeoCoordinate>>(
handler => geoCoordinateWatcher.PositionChanged += handler,
handler => geoCoordinateWatcher.PositionChanged -= handler)
.Select(ep => ep.EventArgs.Position);
geoCoordinateWatcher.Start();
geoCoordinateService.StatusObservable
.ObserveOnDispatcher()
.Subscribe(this.OnStatusChanged);
geoCoordinateService.PositionObservable
.ObserveOnDispatcher()
.Subscribe(this.OnPositionChanged);
Option 1
Subscribe before starting your watcher:
geoCoordinateService.StatusObservable
.ObserveOnDispatcher()
.Subscribe(this.OnStatusChanged);
geoCoordinateService.PositionObservable
.ObserveOnDispatcher()
.Subscribe(this.OnPositionChanged);
geoCoordinateWatcher.Start();
Since you have given limited information, I have no reason to believe this is insufficient.
Option 2
Use Replay to define an IConnectableObservable<T>, then Connect prior to starting your watcher:
var status = geoCoordinateService.StatusObservable.Replay(1);
var position = geoCoordinateService.PositionObservable.Replay(1);
var statusConnection = status.Connect();
var positionConnection = position.Connect();
geoCoordinateWatcher.Start();
status.ObserveOnDispatcher().Subscribe(this.OnStatusChanged);
position.ObserveOnDispatcher().Subscribe(this.OnPositionChanged);
This second option is necessary if you really do need to perform your subscription at a later time than you start your watcher.

Adding text to RichTextBox Async #C / WPF

What I am trying to achieve is to add text after every operation to a RichTextBox.
The problem is, that these operations take some time and instead of viewing the appended text after every operation finishes, I view them all at the end of the routine.
Semi-Pseudo code:
RichTextBox richTextBox = new RichTextBox()
if (Operation1())
{
richTextBox.AppendText("Operation1 finished");
if (Operation2())
{
richTextBox.AppendText("Operation2 finished");
if (Operation3())
{
richTextBox.AppendText("Operation3 finished");
}
}
}
The problem is that I view the appended text of operation 1 & 2 after the operation 3 is finished.
I read somewhere that I need to use something called BackgroundWorker???
Using BackgroundWorker, you would just put the background work into DoWork, and the update into RunWorkerCompleted:
var bw1 = new BackgroundWorker();
var bw2 = new BackgroundWorker();
var bw3 = new BackgroundWorker();
bw1.DoWork += (sender, args) => args.Result = Operation1();
bw2.DoWork += (sender, args) => args.Result = Operation2();
bw3.DoWork += (sender, args) => args.Result = Operation2();
bw1.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation1 ended\n");
bw2.RunWorkerAsync();
}
};
bw2.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation2 ended\n");
bw3.RunWorkerAsync();
}
};
bw3.RunWorkerCompleted += (sender, args) => {
if ((bool)args.Result)
{
richTextBox.AppendText("Operation3 ended\n");
}
};
bw1.RunWorkerAsync();
You'll notice that this runs afoul of "DRY". You could always consider abstracting the tasks for each step using something like:
var operations = new Func<bool>[] { Operation1, Operation2, Operation3, };
var workers = new BackgroundWorker[operations.Length];
for (int i = 0; i < operations.Length; i++)
{
int locali = i; // avoid modified closure
var bw = new BackgroundWorker();
bw.DoWork += (sender, args) => args.Result = operations[locali]();
bw.RunWorkerCompleted += (sender, args) =>
{
txt.Text = string.Format("Operation{0} ended\n", locali+1);
if (locali < operations.Length - 1)
workers[locali + 1].RunWorkerAsync();
};
workers[locali] = bw;
}
workers[0].RunWorkerAsync();
You could do the above 3 times, or use ReportProgress to run all tasks in one background thread, and periodically report progress.
The way that WPF (and most other UI frameworks work) is that there is a UI thread, which handles all the UI events (such as button clicking) and UI drawing.
The UI can't draw things if it's busy doing other things. What's happening is this:
You click a button
The UI thread gets a button click message, and invokes your click handler function
Now, the UI can't redraw or perform any other updates until your click handler function finishes.
Your Operation1 function finishes, and you append to the RichTextBox
The UI can't update because it's still stuck running your code
Your Operation2 function finishes, and you append to the RichTextBox
The UI can't update because it's still stuck running your code
Your Operation3 function finishes, and you append to the RichTextBox
Your function finishes, and now the UI thread is free, and it can finally process the updates and redraw itself.
This is why you see a pause and then all 3 updates together.
What you need to do is make the code that takes a long time run on a different thread so that the UI thread can remain free to redraw and update when you'd like it to. This sample program works for me - it requires .NET 4.5 to compile and run
using System.Threading.Tasks;
...
// note we need to declare the method async as well
public async void Button1_Click(object sender, EventArgs args)
{
if (await Task.Run(new Func<bool>(Operation1)))
{
richTextBox.AppendText("Operation1 finished");
if (await Task.Run(new Func<bool>(Operation2)))
{
richTextBox.AppendText("Operation2 finished");
if (await Task.Run(new Func<bool>(Operation3)))
{
richTextBox.AppendText("Operation3 finished");
}
}
}
}
What happens here is that we use the C# magical async feature, and the order of operations goes like this:
You click a button
The UI thread gets a button click message, and invokes your click handler function
Instead of calling Operation1 directly, we pass it to Task.Run. This helper function will run your Operation1 method on a thread pool thread.
We use the magic await keyword to wait for the thread pool to finish executing operation1. What this does behind the scenes is something morally equivalent to this:
suspend the current function - and thus free up the UI thread to re-draw itself
resume when the thing we're waiting for completes
Because we're running the long operations in the thread pool now, the UI thread can draw it's updates when it wants to, and you'll see the messages get added as you'd expect.
There are some potential drawbacks to this though:
Because your Operation1 method is Not running on the UI thread, if it needs to access any UI related data (for example, if it wants to read some text from a textbox, etc), it can no longer do this. You have to do all the UI stuff first, and pass it as a parameter to the Operation1 method
It's generally not a good idea to put things that take a long time (more than say 100ms) into the thread pool, as the thread pool can be used for other things (like network operations, etc) and often needs to have some free capacity for this. If your app is just a simple GUI app though, this is unlikely to affect you.
If it is a problem for you, you can use the await Task.Factory.StartNew<bool>(_ => Operation1(), null, TaskCreationOptions.LongRunning))) instead and each task will run in it's own thread and not use the thread pool any more. It's a bit uglier though :-)

Working with threads

I am using 3d party library.
And i have the following code:
Session s = new Session(AuthParam.Login, AuthParam.Password);
s.Connect();
s.Connected += (sender, eventArgs) =>
{
_contactCollection = s.ContactList.Contacts.Select(x => new Contact(x.Nickname, x.Uin)).ToList();
};
s.ConnectionError += (sender, eventArgs) =>
{
};
s.Dispose();
s.Connect working in separate thread. So i want stop executing function. Wait while raised events and then continie executing. How can i do it?
Why could you not reorder your code such that the event handlers are added before calling Connect?
Session s = new Session(AuthParam.Login, AuthParam.Password);
s.Connected += (sender, eventArgs) =>
{
_contactCollection = s.ContactList.Contacts.Select(x => new Contact(x.Nickname, x.Uin)).ToList();
};
s.ConnectionError += (sender, eventArgs) =>
{
};
s.Connect();
This way you are guarenteed to get the raised events caused by the Connect method since they are wired in before Connect is called.
There is really no way to prevent Connect from executing once it is called.1
1I suppose you could execute Connect on a separate thread and then suspend that thread, but that is fraught with problems; too many to enumerate here.

Categories