I'm trying to write a drawing library. In this drawing library there is an update function that should update every frame. I do this by using a do while loop See code below:
private void UpdateCanvas()
{
do
{
Canvas.PumpEvents();
if(UserUpdateVoid != null) UserUpdateVoid();
} while (Canvas.Exists);
}
I also have a function in which the user can set their own update function. This function is part of the SharpDraw class, see code below:
public void SetCustomUpdateFunction(Action function)
{
Console.WriteLine("updated the user function");
UserUpdateVoid = function;
Console.WriteLine(UserUpdateVoid);
}
all this is called in the following way:
public class SharpCanvas
{
private Sdl2Window Canvas;
private GraphicsDevice GraphicsManager;
private Action UserUpdateVoid = null;
public SharpCanvas()
{
WindowCreateInfo WindowInfo = new WindowCreateInfo(
200,
200,
100,
100,
WindowState.Normal,
"SharpWindow"
);
CreateCanvas(WindowInfo);
UpdateCanvas();
}
}
And the SharpDraw instance is made in the following way:
namespace test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
SharpCanvas Canvas = new SharpCanvas(200,200);
Canvas.SetCustomUpdateFunction(Update);
}
private static void Update(){
Console.WriteLine("update");
}
}
}
But the problem is that the Console.Writelines in the SetCustomUpdateFunction() are never executed. I guess this has to do with the fact that the while loop keeps the program from further execution. So my question is how do i keep the while loop running while still being able to execute different pieces of code? In unity they are able to do it :P
If there is something unclear let me know so i can clarify!
That is entirely normal. It does not mater if you are running a console application, a Windows Form or WPF/UWP application*: Only one piece of code can be executing. While one piece of code does not return, not other code can run.
You need to add some form of Multitasking into the mix. Now that looks extremely like a Console Application and those are the last place I would advise learning Multithreading in. My personal advise is to start under Windows Forms using the BackgroundWorker. It is dated and rarely used in practice, but it can help you get up to speed with the rules and conventions. But this is one area where you can ask 10 people and get 11 Opinions.
*Web Applciations are semi special. As they are pleasingly parallel and it helps with isolation usually each request is given their own Thread. But at least for each singular request, it still holds true.
When you call UpdateCanvas, you enter a loop and code never goes further. To prevent this, you should use threads, async-await or something similar else (see this answer for async-await).
You have to use Multithreading programming. Look for it on google, there are plenty of examples.
Related
I made a simple app in UWP and I'm having trouble with the EventHandlers not being triggered... I made the same app in Core.NET and it works great if I add "Console.ReadLine()" at the end of the main function so it seems like the thread of the main function dies before EventHandlers can be triggered.
Is there a way, in UWP, for the instance to stay alive a while (ie: timeout) to give a chance for the EventHandlers to be triggered.
Note: This is an example of the problem; the real context will happen in the reception of a web request.
Here's the code:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
test();
}
private async void test() {
Client DiscoverClient;
DiscoverClient = new Client();
DiscoverClient.DeviceHandler += Client_DeviceHandler;
await DiscoverClient.DiscoverAsync();
}
static private void Client_DeviceHandler(object sender, BroadlinkDevice device)
{
int x = 0;
}
}
Instead of using
await DiscoverClient.DiscoverAsync()
you could use
_ = DiscoverClient.DiscoverAsync().Result
This enforces test() to wait for DiscoverAsync() to return.
.Result may only be used if the return type is not void, so you could just let DiscoverAsync() return a boolean when it is finished. The discard is then used to have an assignment that makes the constructor block until DiscoverAsync() is done.
I tried to integrate the library mentioned in your comment into my UWP app, it will throw 'Access Denied' exption when call method GetActiveTcpConnections(line 60 in Network.cs). Since that the event Client_DeviceHandler will not be triggerred. Please see this issue(issue#24369) in github.
This document shows how to use socket in UWP. You may refer the server sample to modify or implement the feature.
https://learn.microsoft.com/en-us/windows/uwp/networking/sockets
I tryed multiple ways found on the internet (some using sockets) but I did'nt find a working solution...
I ended up using a workaround: looping through ip searching for the device's hostname. Since the IP only changes when my router is restarded, the discovery process is rarely needed so even if it's a little on the heavy side, it's quite ok for me :-)
Thanks for you help guys
I've read about VB6's threading model, and found this link very helpful.
With the following points in mind...
Do VB6 event handlers run in separate threads?
Not really, because there aren't separate threads. Your code runs on a single thread, wrapped in the service-like architecture I described above. Most of what you talk to that is threaded is other COM objects which have their own apartments. So to communicate back and forth, you are basically doing RPC calls when the threads talk to each other: you aren't directly manipulating them.
Among other things, the VB6 program had a timer that woke up every 4 seconds, manipulated some global variables and went back to sleep, while the main program was doing its thing. I can't understand why this didn't result in collisions.
The "timer" is on a separate thread created for the timer, but when it calls into your code, you are guaranteed not to interrupt any other functions, because the function calls are basically queued one at a time in the thread.
... I've attempted to implement VB6's event handling behavior in the code below.
ActionManager.cs
public class ActionManager : IDisposable
{
private readonly BlockingCollection<Action> ActionQueue = new BlockingCollection<Action>(new ConcurrentQueue<Action>());
public ActionManager()
{
}
public void Kickoff()
{
// Start consumer thread
new Thread(ExecuteLoop)
{
IsBackground = true
}.Start();
}
public void AddAction(Action action)
{
ActionQueue.Add(action);
}
private void ExecuteLoop()
{
// Blocks until new actions are available
foreach (var action in ActionQueue.GetConsumingEnumerable())
{
action.Invoke();
}
}
public void Dispose()
{
ActionQueue.CompleteAdding();
ActionQueue.Dispose();
}
}
MainForm.cs
public partial class MainForm : Form
{
public ActionManager actionManager = new ActionManager();
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load()
{
// Perform preparatory steps, such as initializing resources,
// configuring settings, etc.
// (Insert preparatory steps here)
// Once preparatory steps are complete, start the ActionManager
actionManager.Kickoff();
}
// Event handler for when the Timer's specified interval has elapsed
private void Timer_Tick(object sender, EventArgs e)
{
actionManager.AddAction(() => {
// (Insert timer event steps here)
});
}
// Event handler for when SomeButton is clicked
private void SomeButton_Click(object sender, EventArgs e)
{
actionManager.AddAction(() => {
// (Insert button click event steps here)
});
}
}
An ActionManager manages an event queue by executing each event one after the other. Any type of event, such as mouse clicks, timer ticks, network packet arrivals, and the like, will enqueue their respective event handling code to the event queue. This way, the code will run "on a single thread," which will also handle the problem of unsynchronized global variables.
Is this a correct implementation? Please share your thoughts!
What you have is a somewhat decent starting place for a custom message loop, if you were to begin writing your own UI framework from scratch. But you're using winforms, you're not writing your own UI framework from scratch. Winforms already has its own message loop that processes messages, and a mechanism for scheduling work to run in that loop. You don't need to create any of that from scratch. All of the events fired from the winforms controls will already be firing in the UI thread, so you don't need to create your own special UI thread and manage scheduling actions into it.
In fact doing so would cause problems, as you would end up having the UI thread that winforms is using to manage its UI objects, and you would have your second thread that you're creating. If you ever used any UI controls in that thread things would break as they are designed to only be used from the winforms UI thread.
(I figured I should ask in the comments first if my suspicion about a legacy app was right.)
Okay, time for the bad news: you should NOT do this. Please, please, please, do NOT do this. I'm telling you as a developer that has been in your shoes that this will NOT end well if you try to go down this road.
Here's what's going on. You've got a legacy app - and it probably does a lot of things that are very important for the company.
But the problem is, it's likely not written very well, it's cranky, and it did not port very well into the modern .NET world.
Now, you can try to go down the road of shoehorning .NET into the VB6 model of the world... but all you've done is kick the can down the road. You've still got a badly-written, cranky legacy app that you're still having to maintain - and worse, you're having to maintain the .NET-to-VB6-threading-approach as well.
I can guarantee you that the correct approach is to Redesign/Rearchitect it. Write out what it does, ask yourself if there's anything you can do to improve the process, and write it from scratch in .NET. Several reasons:
You're going to have a more stable end product
You're going to spend FAR less time maintaining the new product
You'd have to rearchitect the program eventually anyways.
If it helps, let me tell you a story of an old job I had. A coworker and I were both responsible for porting VB6 apps into .NET. He had a tire inspection app, and I had a rubber mixing app.
He tried porting his existing VB6 app into .NET, getting all the language
differences worked out, GUI/Thread issues altered, etc
I sat down with a rep from the user area, and went ahead just
rewriting the rubber mixing app.
... I was done much sooner than the coworker, my app was far more user-friendly, and it was a heck of a lot less of a maintenance issue.
Management likely will not like hearing advice that you should rewrite the whole thing. But you need to push and fight for this. If it helps, point out that most software dev time isn't on new coding, it's on maintaining existing software. It might take more time up front to get it rewritten (even that's not a given) but it'll pay for itself very quickly in the long run.
I have a piece of code that does some calculations and then calls the form.show command. Now I have a library (the revit api) that does not allow me to store variables in a project without being in the main thread.
The logical solution for this is to get the spawned thread to call the main thread using say a producer/consumer pattern with code looking a bit like this:
form.Show(owner);
while(AppIsRunning){
if(clicked)
commit();
else
Thread.sleep(100);
}
However when I do this the gui does not load fully (black background, no text in buttons ext.).
I have also tried doing this using the evoke method
private void BtnOK_Click(object sender, System.EventArgs e)
{
Commit();
Invoke(Commit);
}
private void Invoke(Action commit)
{
commit.Invoke();
}
However this just tells me that it's not the main thread that's executing the commit function.
Is there another way to do this or am I just making an error.
Just to be clear I have a form.show(owner) command that throws an error if it's not executed by the main thread. I also have a commit() function that must be excused by the main thread or it throws an error. The execution must wait until a button press. But the main thread polling the gui thread for changing causes the program to hang. According to my google search it' s also possible to do something involving an external event to get back into the right context but the example given was using python to invoke c# code, is there a good way to raise an external event to get back into a given thread in c#?
Edit: based on some suggestions I have created the following code:
public class ThreadManager
{
static List<ThreadAble> orders = new List<ThreadAble>();
public static bool running = false;
public static void execute(ThreadAble action)
{
orders.Add(action);
}
static System.Timers.Timer timer;
public static void RegisterAPIThreadAndHold(ExternalCommandData commandData)
{
UIApplication uiapp = commandData.Application;
uiapp.Idling += Application_Idle;
}
private static void Application_Idle(Object o,IdlingEventArgs e)
{
if (orders.Count != 0)
{
ThreadAble f = orders.First();
orders.Remove(f);
f.execute();
}
}
}
public interface ThreadAble {
void execute();
}
However this does not appear to actually run when I use it as
public override Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
Form frm = new OverviewForm(ExternalCommandData commandData);
frm.show()
ThreadManager.RegisterAPIThreadAndHold(commandData);
ThreadManager.Execute(new run_ThrowError())
where ThrowError.execute() is
Throw new Exception(" this is actually being executed" );
Your first example could work if you will replace Thread.Sleep by the System.Windows.Forms.Application.DoEvents(). It should give time to paint GUI and do not froze application completly.
form.Show(owner);
while(AppIsRunning){
if(clicked)
commit();
else
{
System.Windows.Forms.Application.DoEvents();
// Thread.sleep(100);
}
}
But this is not perfect solution to achieve this.
Better would be calling Dispatcher.Invoke command inside your dialog to perform MainThread operations.
You can use i.e. GalaSoft library - please refer to DispatcherHelper object documentation and samples.
The two ways to do this I'm aware of are with the External Event or the Idling event.
With the idling event, you'll register it, and while it is registered, your code (in the main thread) will get a callback from Revit every time that it's not busy with something else. Often a few times per second.
Once you are in the Idling callback, then you're able to create transactions and interact with the model. So your callback checks the state of the form and decides whether there is something to do.
The External Event works similarly in terms of registration, but you're able to request a trigger of the callback.
Jeremy Tammik must have 20 posts on thebuildingcoder.typepad.com on Modeless dialog / Revit stuff.
For a simple solution to this, please refer to the Revit SDK ModelessDialog ModelessForm_ExternalEvent sample application. It demonstrates exactly what you are asking for.
I want to write a helper function start that starts pool threads for me but also adds some code before the actual background processing starts in the very same pool thread. So the background thread must do some extra work. I would call start very often and the extra code might change. So I wanted create a kinda factory for pool threads.
Would that be even possible ? If yes, how would I "inject" code into threads ?
I tried this:
class Program
{
private static void test()
{
Console.WriteLine("hello world");
}
private static void start1(Action param1)
{
ThreadPool.QueueUserWorkItem(o =>
{
// extra work is here
param1.Invoke(); // starts another subthread ?
});
}
private static void start2(WaitCallback param1)
{
ThreadPool.QueueUserWorkItem(param1);
}
static void Main(string[] args)
{
start1(new Action(test));
start2(o => { test(); });
Console.ReadKey();
}
}
ThreadPool.QueueUserWorkItem(o =>
{
ExtraWork();
param1.Invoke();
});
is equivalent to
ThreadPool.QueueUserWorkItem(o =>
{
ExtraWork();
param1();
});
Invoking a delegate does not start a new thread. (Why do you think it might?) So this code works just fine as it is. It will invoke the two functions sequentially.
You cannot add random. net code to run by string value. Unless you play with compiler and take the code, compile it into a DLL then call it with reflection i don't see how it can be done. If that's what you need i am scared to ask how the hell you need to do that.
If you do not require to have random code but specific functions well it's your lucky day. Functions can be pass as parameters. you can also build a list of function to get called in order and do it. That you will need to do more search on that, i haven't done this in years. Or maybe fellow stacker can comment and add link to nice article.
If the code need to be randomly generated and is not forced to be .net, example listing file in directory, opening program. Well you can look into scripting language. Worst case you can build a .vbs (Visual Basic Script) dynamically and run it. Then wait for it to create a text file for the results and read it to know what happened.
I have a Windows Form with a status bar which shows the current state of application.
I have a class named AppState with update the Label in the status bar and in dispose it changes the state back to "Ready".
In code when I do an operation like:
using (AppState state = new AppState("Processing..."))
{
//Do some work that take some seconds
}
But the label remains the same. I am not getting any exceptions. The label text is updated but on UI it keeps on showing previous value. Am I missing anything here?
santosc you are right, thats the only thing I am doing. Here is the AppState code
public class AppState : IDisposable
{
static string Default = "Ready";
public AppState(string status)
{
Form.StatusLabel.Text = status;
}
public void Dispose()
{
Form.StatusLabel.Text = Default;
}
}
It's always the same thing...
If you want to start something that takes a while, don't do it within your GUI thread or your GUI will freeze (no updates of label, no resizing, no moving, no whatever).
Filling your code on thousand places with Application.DoEvents() is also a bad practice.
If you have some long running task (long means > 1 sec) you should probably use a BackgroundWorker. Maybe it's a little bit harder at the beginning, but you will love it if your program gets more complex. Due to the fact, that this has already being discussed several time, here is a link with some sample code.
Now that you know the right tool (BackgroundWorker) to solve your problem, you should get it to work (or ask another question about your new specific problem).
Looks like you want to put Application.DoEvents() after setting the StatusLabel text field value. This tells Windows Forms to process the Windows event queue for your form, causing changes to be repainted.
in order to be "thread safe" use Invoke, and test with the InvokeRequired in the form like:
// code outside the myForm:-----------------------
if (myForm.InvokeRequired)
myForm.Invoke(new ChangeLabelEventHandler(ChangeLabel), "teeeest");
else
myForm.ChangeLabel("teeeest");
// code in the myForm:-----------------------------
public delegate void ChangeLabelEventHandler(string newText);
private void ChangeLabel(string newLabelText)
{
this.label1.Text = newLabelText;
}
I'm new to C# stuff, but why can't you just do something like:
private void updateStatusBar(string status)
{
if (StatusLabel.InvokeRequired)
{
StatusLabel.Invoke((MethodInvoker)(() =>
{
StatusLabel.Text = status;
}));
}
else
{
StatusLabel.Text = status;
}
}
When you want to update the status?
Maybe multiple threads could solve your problem.
The easiest way is using a BackgroundWorker.
The reason is that the UI is only able to redraw when the UI thread has nothing else to do. And you are blocking it with your calculation.
use Label.Refresh(); it saves a lot of time.This should work for u