Windows Forms Update Dialogs/Sub Windows Dynamically - c#

In a simulator I am writing I use SFML and OpenGL to create a visualization with some basic OpenGL based GUI. Now I need to add a File Chooser Dialog. I was wondering if I could use System.Windows.Forms.OpenFileDialog and update it's events dynamically similarly to the way OpenCV allows you to update windows by using cv::waitkey().
Since OpenFileDialog.ShowDialog() does not return until the window is dismissed, all I have to do is somehow close the Dialog by updating it's events.
I would rather not have to call Application.Run() and leave it in the background because my application is already built around a main loop and Application.Run() takes over the main thread.

The equivalent call to cv::waitkey is:
Application.DoEvents()
However after reading Use of Application.DoEvents() it appears that Application.DoEvents() is much more fragile then cv::waitkey. It can cause an application to crash if there is no open win form.
Alternative Approach
I decided to switch to GTK# since it lets you process events as they occur by checking whether any events exist in the event queue by calling Gtk.Application.EventsPending(). Then the events can be processed with Gtk.Application.RunIteration() in a while loop like this:
while (Gtk.Application.EventsPending())
{
Gtk.Application.RunIteration();
}

Related

Creating a blocking drop in replacement popup like DisplayAlert() for Maui

I'm updating a very large Windows Forms app to .Net Maui to make it into a cross platform app. Ideally, I would have the time to rewrite everything, but I don't. The client wants it yesterday. I'm already using a ton of the allotted time replacing the Windows Forms style interface with the XAML version. I've tried not to tinker too much with the code since the app was behaving flawlessly. Still, I've had to make a lot of changes because the Maui controls aren't always accessed the same ways as Windows Form's controls. Almost all of the methods and functions in the original app are synchronous. But some of the .Net Maui functions that I use to replace them are asynchronous. One function that is giving me a lot of trouble is the awaitable DisplayAlert(). Execution moves right onto the next statement in the code without waiting for the alert to be displayed or the user to respond. The function can be made awaitable, but to do this, the entire method within which it appears must be marked Async, which creates its own problems. There are literally hundreds of calls to The Windows Forms version of DisplayAlert(). Any solution that isn't basically a drop in replacement is going to cost tons of time.
I've been trying to create a blocking popup function that waits for the user's response before executing the next line of code within a synchronous block of code. In the XAML markup I've defined a popup "panel" with a frame, two labels and 3 buttons. Ideally, the code behind should be a function with the same parameters and behaviors as DisplayAlert() except that it blocks. It should display the panel, wait for a user response (button click/press), hide the panel, and finally return the text string of the button that was clicked...all within the same function.
Using simple method's like while loops to determine if a button was pressed block the thread from detecting that a button was press. Moving the panel display to a different thread than the button press, does nothing since the panel can only be displayed on the main thread. Invoking on the main thread has not been successful...at least not the way I wrote the code. I'm hoping someone can provide a very simple example of a blocking DisplayAlert() function that can be used within a non-async method.

How to properly exit a multi-threaded program

I made a program based on Aforge (it's a video library). This library creates its own refresh events for the next video frame from camera. So far so good, earlier people have helped me with multi threading so these Aforge threads could report back to the main program thread, again so far so good, it works great.
The code can be seen here: how to do multithreading when using outside referenced code.
But now I regularly notice a new program error. The problem starts when I want to exit the program. At the moment the Aforge thread might still be active. And it wants to write back to main form that is closed.
Somehow I need to stop the other thread before I close the program. There is an option in Aforge to do something like camera stop, but it's not enough. But then still my code wants to write on the main form that's already closing.
Is there a way to stop all threads, or some safe way to close from the originating thread? I even placed the back reporting to the main program in a try catch construction but it didn't work well, the only way of stopping it in these situations is to press the stop execution button within Visual Studio itself.
If I understand your problem correctly, you may have an Invoke call about to happen on your form just as you've closed the form. I've had this happen as well.
What I've done is to set a "shutdown" variable when I start to close the form, and then use AppDomain.CurrentDomain.UnhandledException to watch for InvalidOperationException (or whatever you're getting), and ignore if shutdown is set.

Creating a Form and using Form.ShowDialog on a background thread

Using Winforms,
If I'm on a thread that is not the "main" ui thread can I safetly
Create a Form,
Call ShowDialog on that form
It seems like I would be obeying the rule of:
Winforms controls must be modified on the thread they were created in.
From some of the reading I've done it seems like ShowDialog will create its own message pump so that I don't need to worry about the Form being created on a thread that already has a message pump.
The background of the question is that I get a callback where I'd like to display some Winforms UI, but I don't have access to any other UI that I could use to Invoke to the main thread.
That's roughly correct, albeit that it is pretty important that you call the thread's SetApartmentState() method to switch the thread to STA. Important for many UI operations, including the clipboard, drag and drop and the shell dialogs. And that you usually have a crummy Z-order problem when the form that you create on the thread is not in the foreground and hides behind another window. Or has the nasty habit of actually do move in the foreground when the user doesn't expect it and grab a mouse click or keystroke unexpectedly.
These are hard problems to fix, they do make your app flaky. There's no good reason to not have a reference to invoke to, you can also pass it to the class some way some how. You've always got Application.OpenForms[0] to fall back on, if really necessary.
Yes, you can do that, but if you want the dialog to actually act like a modal dialog (i.e., block the parent Window, which I assume you want since you are calling ShowDialog) then be prepared to be disappointed.
What problem are you actually trying to solve here. It sounds like you want a modal dialog that doesn't block, which is a bit strange. If you explain the problem at hand there may exist a solution you have not yet considered.

Open new form from inside each thread?

I'm using the following code to open a new form (that is for user input) in my function:
Form4 f4 = new Form4();
f4.mainform = this;
f4.get_Text(matchString);
f4.ShowDialog();
It's working perfectly when not threading, but when I try to run the function on two threads I only get 1 form popup. How can I adjust it so that it will support more than one thread?
You can open a form from any thread, you just need to start a message loop on the new thread, such as:
Application.Run(f4)
The Run method will not return until the form is closed. It can cause issues, though, so you need to be careful and know what you are doing. Unless it's a real pain to do, I would sooner consider redesigning your code to be more asynchronous. For instance, you could create a event handler method to listen for the form's closing event.
The WIN32 Message pump runs on one thread -- the GUI thread. As soon as you .ShowDialog(), the c# stops until the user closes the dialog. Even if you use .Show() to avoid a "stop and wait for the user to push ok", you still must handle all GUI events on the GUI thread by .Invoke()ing to the GUI thread.
The way to support multi-threaded-ness is by doing non-GUI work on alternate threads.
ShowDialog does pump messages so it would technically work on a separate thread without needing a dedicated message loop. However, what you currently have looks like a recipe for disaster because that form appears to hold a reference to another form via f4.mainform = this and it is presumably trying to access it. You simply cannot do this without littering (and I mean that literally) your code with a bunch of Invoke or BeginInvoke calls.
Furthermore, running UI forms on a thread other than the main UI thread generally does not work well. There are a few obscure problems you can run into. For example, since there would be two UI threads in play it is possible to have 2 active modal dialog boxes open. One might be hidden behind the other and the end user would not see it. This reason, among others, is why it is not generally recommended to use more than one UI thread.
My advice is to figure out a way to make this work with a single UI thread. Your life will be simplier if you do.

Handling minimized programs

I need help handling minimized programs when using a custom/self made explorer.exe file .. because unless properly handled, minimized programs will just shrink to something like 100x50px and stay on screen. I worked out a Timer in C# to check for "iconic" processes, list their mainWindowHandler, and move them outside the screen with "MoveWindow". To bring them back I use the handler and the "ShowWindow" function wich works AWESOME .. but as I said, it involves a constantly running Timer, so there must be a cleaner/easier way of achieving this.
Any ideas? Some way to hook and raise an event when a window is minimized?
*please note: show and movewindow are functions from user32.dll. I'm not trying to catch when MY forms are minimized, but when the OTHERS programs are.
You can create a hook to check when windows are being minimized.
I found a CodeProject article that uses hooks to check when the user opens a system menu (ALT+SPACE) on any window, and then appends an extra item to it. You can use that code to check when the user hits the minimize button, and run whatever code you need there.
The CodeProject article is written in C++, but you can adapt the same method for C# (or use P/Invoke).

Categories

Resources