I'm developing a Revit add-on which performs some lengthy tasks. During the process, I want to display a simple WPF window with an indeterminate progress bar, a label to inform about current process and a button to enable aborting.
I already tried the most obvious ways of accomplishing that: creating a WPF window inside the add-on and displaying it, but the problem is that the UI gets frozen, no matter how I implement this. During some processes, the whole Revit UI gets frozen/white so I really wouldn't expect my embedded WPF window would behave normally in these conditions anyway.
The workaround I figured out was to have the WPF window as a separate app (EXE file) I could run from the add-on. I based my implementation on this example .
The good part of it is that it doesn't hang no matter what is happening with Revit.
The bad part is that the sequence of how Windows is queuing the calls of my separate WPF app is sometimes different from the sequence of these calls from my add-on. It sometimes results in a situation when the Revit process is over but the WPF window is still displayed (waiting for the final, closing call which had been apparently already executed, but then the app got reactivated with another, delayed call).
Preferably I would like to handle the WPF app the same way as you can i.e. handle an Excel application from .NET. You create an ExcelApp object, do what you want with it and dispose of in the end.
The problem is I don't have a clue of how to do this.
How should I expose the WPF app's API to my add-on?
Could it be possible to have the WPF app responsive and controlled from the Revit add-on at the same time? (user can still click the abort button, the indeterminate progress bar doesn't freeze)
The First thing to know is about interacting between two processes. there are some Standard approaches:
Interacting through Socket (Socket Programming)
Using Named PipeLines (Useful when your messages aren't so long)
There are some other predefined Libraries based on above techniques. Using a FileSystem Based method is not a reliable way to proof the outputs.
This was a part of your solution. The next step is to use Threading in your WPF application. I'm not familiar to Revit and I don't know how it works.
UI freezing is normal in a long running process. because UI is busy and it can't answer your requests (e.g Mouse Move, Click, ...). So using a Thread you can put your long running process into a separate place and wait for the response at the end of it.
There is a problem while using a Thread. Because you left your UI and started your long running process on a separate Thread, you can't directly access to your ProgressBar. In this situations you have to use ThreadDispacher. It's not a terrifying concept, it just a three line of codes that will adds to your callings.
for example:
Dispatcher.Invoke(() =>
{
ProgressBar.Value++;
});
Search for a Library to doing your IPC (Inter Process Communication) to get the result faster (or you can learn about above techniques to do it by your means) and next add a simple thread to your WPF application so you be able to Start, Pause and resume the running job based on the situation.
Related
I have a windows application that reads from a database and populates multiple Listview containers depending on what items the user selects. Some of the data in a particular Listview is right-clickable with a MenuItem option to ‘Write Data to Excel’. This may take around 10 minutes to complete.
I have the Excel Interop portion written in stand-alone code or can I incorporate it into the application project. The Excel Interop app takes only 1 parameter to do its thing.
My question is… should I incorporate it into the Windows App and use multithreading or run it as a standalone app (which seems more efficient), which is called from the Windows App? And what is a good way of doing that where the Windows app starts the process and then can forget about it.
I think that the answer for this one is answered by the question : "What should happen if the user closes the main application during those 10 minutes ?"
If the file should still be wrote, then a standalone application is perfect, cause your threads won't survive.
If the file creation should be interrupted, then I see no reason not to use multithreading, as it seems simpler by default, in particular debugging this part of the code is way easier if it's in the same application.
I would recommend for the below flow:
We can create our own queue which will be either maintained in database or file system.
Then we can write a scheduler which will fetch all the unprocessed request and with the respect to response mark appropriate status of queued item.
Now You application can just call the queuing process and move forward from there.
Use another thread to write it.
I am working on a application, which would be the face of lot of other tools running in background. I am facing an issue. During the launch of a background application ,it needs to load a specific file(file-->load--> file name).
Let the front end application be Fapp and the background application be Bapp. Is it possible for Fapp to get the handle of Bapp's menu item and trigger the load function. I am able to get the handle for buttons but not able to do the same for menu items.
Now we are achieving this using AutoIt, I am trying to achieve this in C# itself.
After you have obtained the handle of the window that you want to invoke its menus, then you may use
HMENU GetMenu(HWND) windows api to get menu
HMENU GetSubMenu(HMENU, int) to get to the file menu and again to open menu.
BOOL GetMenuItemInfo( ... ) to get info about menu
and you can use PostMessage((IntPtr)hWnd, WM_COMMAND, 0, ID_MENU_ITEM); (related post) to perform a click on that item.
all these apis are what AutoIt calls (I think). This solution works if your Bapp is a normal windows application with a normal windows menu, not a fancy WPF app, or a ribbon. If this is the case, then what you see as menu probably is not a menu (technically anyway)
Are you sure this is the right way to get two applications talking to each other?
If you don't have source code for BApp, and it also doesn't have an API that you can use, then pretending to be an interactive user could be the only way to interact with it. Just be aware that it is fraught with issues, consider what will happen when
BApp isn't already running
BApp has a modal dialog open
BApp is in the middle of an operation (or hanging) and its menu is disabled
BApp is updated to a new version and its UI changes
An interactive user changes focus, in the middle of an operation.
An alternative to this would be to do the same thing that you do when you are unit testing an application with a UI. This is because you are doing the same thing, automating an application by making calls that execute its functions, in this case to test the results are as expected. Since this is a WPF post lets assume that you are writing an application with MVVM, and the best way (to avoid brittleness when we are change the UI) is to ignore the UI (View) and call the layer that sits underneath i.e. the VM (ViewModel).
In fact its quite easy just to add a self-hosted WCF connection inside your BApp application so that it can be called externally.
this._host = new ServiceHost(service);
this._host.AddServiceEndpoint(typeof(IContract), new NetTcpBinding(), address);
this._host.Open();
This would then enable you to get the two talking totally independently.
If your Bapp is able to somehow invoke Win32 API - then this can be achieved by sending a custom WM_USER message to your Fapp - using SendMessage(). In your Fapp you handle this message and take appropriate action.
I don't think getting handle to a control and invoking its handler is the right way.
I have a console application that shows latest activities & status on its console. The application is heavily threaded & performance is the major concern. No user interactivity is required. Due to a recent case, ive been asked to migrate it to a win form application.
Initial post ->
How to programmatic disable C# Console Application's Quick Edit mode?
So to encounter the problem, I have used Application.Run(ApplicationContext context) so to start a message loop in my console application so that i can hook and trap mouse events and can reset quick edit mode at runtime. I have also deleted a Console's default menu item "Edit" that emerges on right click so not to allow the user to Mark/Copy/Paste.
I want to know what should be the optimal solution, migrating to win form or console app (considering changes i made). Also i need to call Invoke every time in order to put the task in UI's queue so to print the message if migrated to winform.
WinForms would definitely give you more flexibility in what you can do with the UI.
In terms of performance, you really need to be doing a lot of UI updates in order for performance to be a concern. It sounds like that will not be the case since you're currently getting it done with a console application. Most of the time, the UI performance is affected not because the UI thread can't keep up with the updates, but because non-UI stuff (e.g. file IO, database queries, etc.) is done within the UI thread.
I would consider to change your application so that it streams it's output into a logfile, a lightweight database or a Windows event log instead to the console. Thus your application won't need a console or UI at all and can be alternatively run as a service. If someone wants to see that messages, give him a separate (probably Winforms) program to view the latest output, or if you use the Windows event log, he can just use the Windows Event viewer to check the output of your program.
So you neither have to migrate you application to Winforms, nor do some ugly console hacks.
To process log files, the Microsoft log parser may be of interest for you.
I've written a WPF/C#-based "shell" which launches WPF apps or other apps.
What would be the best method for checking if the process is finally fully launched or no longer "busy"? I've noticed that the mouse cursor for the launched process stays at the busy cursor from initial launch until I can finally see the UI for the process. Could I use User32.SetCapture API to set the mouse capture to the external process, then somehow check if the mouse cursor is the busy cursor? Or perhaps there's a mechanism in the System.Diagnostics.Process class that I'm unaware of?
As some of the launched apps are pre-compiled third-party apps, I absolutely cannot implement a mechanism in the external processes to message if it is finally ready, such as: Microsoft PowerPoint 2010 Viewer, Adobe Acrobat, or Adobe Flash Player Standalone.
I can't just check if the process has been created, because then I have a blank, unresponding window and a busy cursor. I hope to hide my WPF app the moment the external process is done launching.
The WaitForInputIdle Win32 APi function will wait until given process enters the message loop (with no input pending).
Quote: "Before trying to communicate with the child process, the parent process can use the WaitForInputIdle function to determine when the child's initialization has been completed."
You can call it via P/Invoke.
Not very cear what do you mean saying "beasy", but hear are several considerations:
There is no known (clear) way, at least that I'm aware of, that can let you do something like that. The thing is that process is perfectly isolated OS kernel citizen. So you can not write something that works for all type processes, especially if they are 3rd part binaries.
What you can try to do, is get the MainWindow of the process (if there is any), get its handle, and filter OS messages untill you get for example WM_ACTIVATED.
But even if this could work in certain situations, in others can measurably fail. For example, process loaded but the program is not active, cause for some reason License window of the application appeared.
Let's see what others suggest, in my opinion, there is no generic and no single solution to cover minority of possible cases.
Good luck
I recently started programming in WinForms using C#. I have a requirement where I need to search a set of folders and the sub-folders and display the status information to a textbox as I do the search like -
Looking up folder "C:\Windows"...
Found 8 files...
Copying file 1 of 8 to "D:\Temp"...
I have a method which does all the searching and stuff. I don't know how to display the status messages (like above) to a textbox periodically. Currently, the form waits for the method to be complete, and displays the messages all at once. I want them to be displayed one by one as the method progresses.
Thanks in advance.
To properly solve this your searching function will need to be running on a background thread. If the searching occurs on the UI thread it will block updates to the display preventing a periodic status message from being displayed.
The easiest way to do this in a WinForms application is to use a BackgroundWorker. It has a minimum of support for running a task on a background and returning progress information to the UI thread. Additionally there are a lot of tutorials available online to get you started with a solution.
use a BackgroundWorkerThread and the ReportStatus function. That way your UI will be responsive while the search takes place.
Run the method that performs searches on a separate thread (if you're not doing so already). It's quite easy using the async delegate features in .NET.
You can then write to the text box from the worker thread using Control.BeginInvoke() - you must do this because access to UI control sis affinitized to the single UI thread.
You can also create a background worker thread and use the ReportProgress method to notify the UI of updates. There's a fairly complete example of this approach available here that you can download and examine.