Async UI update - c#

I started programming just few month ago so I am a pure beginner
but I needed a math app with Heavy probability calculation and an UI to view/interact so I searched around and found C#.net was the best way... fantastic power...
It will help me a lot to progress if I am able do this :
Wpf window with textbox, in textbox a number is printed each time the calculation is done but the Ui should respond everytime
I tried to do it using latest net 4.5 because the app need to be fast (so use the most recent tech and not timer or background task)
and it work but the Ui is stuck and cannot move (because of my bad access to the text box I think)
If guys could help me it will be great and I thank you all because I learned a lot with your posts!
Here is my wrong newbie code
private Random rng;
public MainWindow()
{
rng = new Random();
InitializeComponent();
Task.Run((Func<Task>) Calc);
}
private async Task Calc()
{
while (true)
{
textBox1.Dispatcher.Invoke
(DispatcherPriority.Normal
, new Action(delegate()
{
textBox1.Text = rng.NextDouble().ToString();
}
)
);
}
}

You're tightlooping, admittedly in a non-UI-thread, but adding a bazillion delegates to invoke in the UI thread... so your UI is just too busy.
All your work is basically going on in the UI thread at the moment - you're not even computing rng.NextDouble() in the background thread.
Also note that you've got an async method without an await expression, which should have triggered a compiler warning - you should take heed of that.
You say you don't want to use a "background task" - but that's exactly what you are doing by calling Task.Run.
Now I'm assuming your real code doesn't actually just need to create random numbers. What does your real calculation code look like, and which thread does it occur in?

Related

(C#) BackgroundWorker() ProgressChanged not working

I have a WPF application that consist of two threads simulating an enterprise producting and selling items in 52 weeks (only one transaction is allowed per week). I need to use a background worker as well so that I can display the data in a listview. As of right now, my UI freezes when clicking on simulate but I can see that the output is still working in the debugging terminal. I have tried everything that I can think of and to be honest, I have had the help of my teacher and even he couldn't find a working solution.
What is freezing my UI when I call Simulate() ?
When my code is different and my UI isn't freezing, my listview never updates because it seems that DataProgress() doesn't work — e.UserStart is never iterating.
Simulate button calls :
private void Simulate(object sender, RoutedEventArgs e)
{
// Declare BackgroundWorker
Data = new ObservableCollection<Operations>();
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync(52);
worker.DoWork += ShowData;
worker.ProgressChanged += DataProgress;
worker.RunWorkerCompleted += DataToDB;
Production = new Production(qtyProduction, timeExecProd);
Sales = new Sales(qtySales, timeExecSales);
Thread prod = new Thread(Production.Product);
prod.Start();
Thread.Sleep(100);
Thread sales = new Thread(Sales.Sell);
sales.Start();
}
DoWork : ShowData() :
Console.WriteLine("Simulation started | Initial stock : 500");
Production = new Production(qtyProduction, timeExecProd);
Sales = new Sales(qtySales, timeExecSales);
while (Factory.Week < max) // max = 52
{
if (worker.CancellationPending) // also this isn't reacting to worker.CancelAsync();
e.Cancel = true;
// My teacher tried to call my threads from here, but it breaks the purpose of having
// two threads as he was just calling 52 times two functions back to back and therefore
// wasn't "randomizing" the transactions.
int progressPercentage = Convert.ToInt32(((double)(Factory.Week) / max) * 100);
(sender as BackgroundWorker).ReportProgress(progressPercentage, Factory.Week);
}
ProgressChanged : DataProgress() :
if (e.UserState != null) // While using debugger, it looks like this is called over & over
{
Data.Add(new Operations()
{
id = rnd.Next(1,999),
name = Factory.name,
qtyStock = Factory.Stock,
averageStock = Factory.AverageStock,
week = Factory.Week
});
listview.ItemsSource = Data;
}
RunWorkerCompleted : DataToDB() :
// Outputs "Work done" for now.
In case you want to know what happens when I call my threads, it looks like this :
Sell() :
while (Factory.Week <= 52)
{
lock (obj)
{
// some math function callings¸
Factory.Week++;
}
Thread.Sleep(timeExecSales);
}
Should I use a third thread just for updating my listview? I don't see how as I need it to be synced with my static variables. This is my first project for learning multithreading... I'm kind of clueless and flabbergasted that even my teacher can't help.
On the one hand, there isnt enough context in the code posted to get a full picture to answer your questions accurately. We can, however, deduce what is going wrong just from the code you have posted.
First, lets try to answer your two questions. We can likely infer the following:
This code here:
if (e.UserState != null)
{
Data.Add(new Operations()
{
id = rnd.Next(1,999),
name = Factory.name,
qtyStock = Factory.Stock,
averageStock = Factory.AverageStock,
week = Factory.Week
});
listview.ItemsSource = Data;
}
You are using a Windows Forms background thread object to try and update a WPF GUI object which should only be done on the main GUI thread. There is also the obvious no-no of never updating GUI objects from non-UI threads. Using BackgroundWorker also has its own issues with threading (foreground/background), contexts and execution, as it relies on the Dispatcher and SynchronizationContexts to get the job done.
Then there is the curiosity of setting the binding over and over in this line:
listview.ItemsSource = Data;
Let's put a pin in that for a moment...
There is, as the other commenter pointer out already, no exit strategy in your while loop:
while (Factory.Week < max) // max = 52
{
if (worker.CancellationPending) // also this isn't reacting to worker.CancelAsync();
e.Cancel = true;
// My teacher tried to call my threads from here, but it breaks the purpose of having
// two threads as he was just calling 52 times two functions back to back and therefore
// wasn't "randomizing" the transactions.
int progressPercentage = Convert.ToInt32(((double)(Factory.Week) / max) * 100);
(sender as BackgroundWorker).ReportProgress(progressPercentage, Factory.Week);
}
But thats not the bigger problem... in addition to the misuse/misunderstanding of when/how many/how to use threading, there doesnt seem to be any kind of thread synchronization of any kind. There is no way to predict or track thread execution of lifetime in this way.
At this point the question is technically more or less answered, but I feel like this will just leave you more frustrated and no better off than you started. So maybe a quick crash course in basic design might help straighten out this mess, something your teacher should have done.
Assuming you are pursuing software development, and since you have chosen WPF here as your "breadboard" so to speak, you will likely come across terms such as MVC (model view controller) or MVVM (model view view-model). You will also likely come across design principles such as SOLID, separation of concerns, and grouping things into services.
Your code here is a perfect example of why all of these frameworks and principles exist. Lets look at some of the problems you have encountered and how to fix them:
You have threading code (logic and services - controller [loosely speaking]) mixed in with presentation code (listview update - view) and collection update (your observable collection - model). Thats one reason (of many) you are having such a difficult time coding, fixing and maintaining the problem at hand. To clean it up, separate it out (separation of concerns). You might even move each operation into its own class with an interface/API to that class (service/ micro-service).
Not everything needs to be solved with threads. But for now, lets learn to crawl, then walk before we run. Before you start learning about async/await or the TPL (task parallel library) lets go old school. Get a good book... something even from 20 years ago is find... go old school, and learn how to use the ThreadPool and kernel synchronization objects such as mutexes, events, etc and how to signal between threads. Once you master that, then learn about TPL and async/await.
Dont cross the streams. Dont mix WinForms, WPF and I even saw Console.WriteLine.
Learn about Data Binding, and in particular how it works in WPF. ObservableCollection is your friend, bind your ItemsSource to it once, then update the ObservableCollection and leave the GUI object alone.
Hopefully this will help you straighten out the code and get things running.
Good luck!

Stop a loop without threading C#

sorry if this is a silly question, I am new to C#, so please give me a break.
I am working on Revit API. currently, Revit API doesn't support multi-threading operations.
my question is how to stop a loop without calling a new thread?
I am trying to get a snapshot and I am waiting for the user to pick a snap, so I put an infinite loop till the condition meets
while (!Clipboard.ContainsImage()) //loop till user get a clipboard image
{
}
but what if I want to abort this???
I have tried
private void Abort_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
abort = true;
}
}
but this method requires threading ....any suggestions!!
You want to look into asynchronous processing patterns in Revit - check for instance The Building Coders description of IExternalEvent.
It might take a little while to wrap your head around it, but let me try to explain:
Split your code up into two parts: The first part runs up until the moment you ask the user to pick a snap (I'm assuming this happens in another application?). In a separate thread, poll the clipboard (or register your application as a clipboard viewer) in your while loop. Don't forget to Sleep() while you're polling! As soon as your polling thread finds a picture, create an instance of an IExternalEvent subclass and post it to Revit. When Revit has some spare time, it will execute the Execute method, passing in a UIApplication that you can use to do the rest of your code.
Revit doesn't let you access it's API from multiple threads at the same time, but during the Execute method of an IExternalEvent subclass, you are guaranteed to be in the correct thread for running code.
You can also look into the OnIdling event - basically, this gets called each time Revit has some spare time too. So instead of using a while loop in a separate thread, you could just place your clipboard checking code in the event handler for the OnIdling event and create a mechanism (a flag) to tell you wether you are currently waiting for a snap or not...

Updating Text Box

I'm writing a program to help with a game. I need it to update the text box that shows the current exp value, on the forum load it does show the exp, I need it to update the exp like every 3 seconds.
How would I go about doing that?
Here is what I have so far:
Client C = Client.GetClients()[0];
Player P;
P = C.GetPlayer();
expTextBox.Text = ("Experience: " + P.Experience.ToString());
I am not sure if I need a timer (which i have tried and I am very bad at making) or if a backGroundWorker would be best.
Based on your comments, I would recommend that you update your UI when your player/s are attacking, and not use a timer. This will keep your UI the most up-to-date and will probably serve you better than a 3 or 10 second timer. You will have a method like this:
public void Attack(Enemy e)
{
//do your attack code
//did the enemy die?
KillEnemy();
//add exp just for landing a successful attack
AddExp(e);
}
public void AddExp(Enemy e)
{
CurrentPlayer.Exp += e.ExperienceGain;
//update the UI with the new exp
GameWindow.ExperienceBox.Text = CurrentPlayer.Exp;
}
This is of course more pseudocode, because I have no idea what your design looks like, but I've made quite a few games, and this is how I always do it.
Good Luck!
I would encourage you to use Timer if you go to the background worker with infinite loop that is okay but you need to take care of two things when you use background workers:
Updating textbox or any other UI won't work as it needs to be done from the main thread. so you need to check myTextbox.requireInvoke() function before.
Check if the background worker got a cancel signal to exist the infinite loop.
on the other side. you will consume some time when you use timers to update the text box. as the timer would go to the event processing cycle in the windows then fire the event and finally you will write the code in the timer event.

BackgroundWorker with SqlConnection

I know I'm having a massive derp moment here and this is probably quite easy to actually do - I have had a search around and read a few articles but i'm still struggling a little, so any feedback or pointers to useful resources would be greatly appreciated!
Anyway I have a class called PopulateDatagridViews which I have various functions in, one of which is called ExecuteSqlStatement, this function is simple enough, it initializes an SQL connection and returns a DataTable populated with the results of the SQL query. Within the same class I also have various functions that use string builders to build up SQL statements. (Not ideal, I know.)
I create a PopulateDatagridViews object in my GUI thread and use it to set various datagrid views with with the returned DataTables. For example:
dataGridViewVar.DataSource = populateDgv.GetCustomers();
Naturally a problem I'm having is that the more data to be read from the database, the longer the U.I is unresponsive. I would like to shift the process of retrieving data via the PopulateDatagridViews to a separate thread or BackgroundWorker so as prevent the main GUI thread from locking up whilst this is processed.
I realise I can create a BackgroundWorker to do this and place in the DoWork handler a call to the appropriate function within my PopulateDatagridViews.
I figure I could create a BackgroundWorker for each individual function inside my PopulateDatagridViews class, but surely there is a more efficient way to do this? I'd very much appreciate a point in the right direction on this as it's driving me around the bend!
Additional Info: I use version 4.0 of the .Net framework.
I strongly suggest that you use TPL (Task Parallel Library) http://msdn.microsoft.com/en-us/library/dd537609.aspx
In your case you will create first task to pull some data and than start second task after first is completed to update UI.
I`ll try to find code that i write for similar problem.
Edit: Adding code
Task<return_type> t1 = new Task<return_type>(() =>
{
//do something to take some result
return some_result; //return it
});
t1.Start();
Task t2 = t1.ContinueWith((some_arg_that_represent_previous_task_obj) =>{//ContinueWith guarantees that t2 is started AFTER t1 is executed!
//Update your GUI here
//if you need result from previos task: some_arg_that_represent_previous_task_obj.Result //Your dataset or whatever
}, TaskScheduler.FromCurrentSynchronizationContext()); //VERY important - you must update gui from same thread that created it! (you will have cross thread exeption if you dont add TaskScheduler.FromCurrentSynchronizationContext()
Hope it helps.
Well in that case I recommend reading this msdn article to get some ideas. Afterwards you should look for some tutorials, because the msdn is not the best source to learn things. ;o)

Threading in C# with XNA KeyboadInput

I am a bit new to threading (not new to C#, just haven't done much threading). Can someone explain to me why this does not work?
I have a thread which calls a method I will call "Loop". Loop contains a while loop which will continuously run, and on every loop of the while I want it to check if the A Key is down (using Microsoft's Keyboard class within the XNA Framework). But for some reason it never registers that anything is being pressed.
static Thread thread = new Thread(Loop);
static bool abort = false;
public static void Begin()
{
thread.Start();
}
private static void Loop()
{
while (!abort)
{
if (Keyboard.GetState().IsKeyDown(Keys.A))
Console.WriteLine("A pressed.");
}
}
Might anyone know why the Console.WriteLine() is never being called?
EDIT:
I guess I should explain a little bit. What I am actually trying to do is create something similar to ActionScript's events in C#. So I want to pass a "condition" and an "action" to call if that condition is met in this separate class which contains this thread. What this would do would allow me to just add "event listeners" to objects and it would automatically constantly check if one of the events gets triggered, rather than leave it to me to write If statements in code to check for the events.
Upon trying to do so, the first thing I tested was regarding this XNA Keyboard stuff, because it was one of the reasons I originally wanted to build this system, but it didn't work. So I created the standalone code which i posted above to see if I had made an error in my previous code and it still didn't work.
I never use XNA so I didn't really "know" but I've run into similar situations where you can't get keyboard (and other) input from a worker thread. I googled and found that in XNA this does seem to be the case. See this for example
So you need to (and probably want to) process your game input in the GUI thread. Just checking for input on each update tick should be fine. I doubt even if it did work, you would gain any performance - and you might introduce some interesting synchronization bugs ;-)
It does look like your creating your worker thread properly - this just isn't an application for it.

Categories