Open modal dialog in WPF to get credentials for CefSharp - wpf

I have a WPF application which is hosting a conversation window from skype for business; the window can open an child control, a Chromiun web browser (CefSharp).
The browser opens a site that needs credentials, so the method GetAuthCredentials is override in order to process the request.
The code goes like this:
AuthBox dlg = new AuthBox();
dlg.Owner = _parent;
dlg.ShowDialog();
callback.Continue(dlg.Username, dlg.Password);
The problem is: I need to make this dialog as modal, in order to lock the parent window (the conversation); for that reason, dlg.Owner = _parent; is added. However this throws an exception:
System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'
To use dispatcher.BeginInvoke doesn't work.
Is there any other way to open the login window (modal) avoiding this threading issue?

I assume dispatcher.BeginInvoke doesn't work for you because it doesn't block?
Try using a synchronization primitive, such as ManualResetEvent, open the dialog in UI thread, in calling thread wait for ManualResetEvent notification, and make sure dialog raises the event when done.

Related

Dialog appears behind other windows

I'm using the Prism dialog service to create an unhandled exception dialog. I have a splash screen window that, while it doesn't have the TopMost property set (tried that and it was totally miserable :), I use Activate on it to get it to rise to the top so it appears over the main window as it loads up.
The problem is when an exception is thrown and the unhandled exception dialog that I made pops up, it appears behind the splash screen, leaving the user wondering what happened until they notice an extra button in the task bar.
The dialog is a UserControl, as instructed by the documentation, and it has no Activate function. And when I try to get a handle to the parent window in the constructor, the Parent property is null.
How can I bring a dialog to the top of other windows?
Prism's dialog service sets the Owner of a dialog automatically to the first active Window that is found in the Application.Current.Windows collection if the dialog window does not already have set an owner. It does not expose any methods to access or activate windows directly. In an MVVM service you would not do that.
In Prism <= 7.x, you can only have a single dialog window host. By default this is a regular Window. You have to share this dialog host window type for all of your dialogs, so setting a different Owner in a custom Window is not an option. Since Owner is null when a Window is instantiated, its owner will be the first active window.
This behavior is problematic if you want the Owner of your dialog to be a different window like your splash screen, so it appears on top of it automatically or modally or have no owner at all.
You cannot activate the dialog in the constructor of your UserControl, as it cannot be set as the Content of the parent dialog host Window before it is instantiated. You either have to use the Application.Current.Windows collection to find the dialog or create a custom dialog service for now for both activating or setting an Owner.
Application Windows
If you want to find the dialog host window in Application.Current.Windows, you can filter this collection after showing the dialog and check the Content of each window, one will contain your UserControl type. If you only show the unhandled exception dialog once, there will be a single window instance with this UserControl. If you show it multiple times, you could identify the current instance via a property on its view model accessible by DataContext that you have set before by passing a DialogParameter in Show. Consider creating a service.
Custom Dialog Service
Personally, I prefer creating a custom dialog service, as it gives you more control over what you are doing. To create a custom interface that exposes the methods of the built-in IDialogService, as well as your own methods, depeding on your requirements.
public interface ICustomDialogService : IDialogService
{
public void ShowOrphan(string name, IDialogParameters parameters, Action<IDialogResult> callback);
}
I simply create a new method ShowOrphan to show a dialog that has no owner and is activated automatically when shown, so it is in the foreground. Adapt it to your requirements, like passing in an explicit owner or just an owner type, so that the dialog service searches an instance in the application window collection itself.
Next, implement the ICustomDialogService in a CustomDialogService type. You can just copy the code from the public repository. Be sure to use the code for your version of Prism, see Tags.
You do not have to change much. Just pass appropriate parameters from your new public method down the ConfigureDialogWindowProperties method, which is responsible for setting the window owner. If activating the dialog window is really necessary apart from showing it, you can do that in ShowDialogInternal.
public class CustomDialogService : ICustomDialogService
{
// ...other public members.
public void ShowOrphan(string name, IDialogParameters parameters, Action<IDialogResult> callback)
{
// Appended a new parameter "isOrphan"
ShowDialogInternal(name, parameters, callback, false, true);
}
// ...other private members.
// Appended a new parameter "isOrphan"
void ConfigureDialogWindowProperties(IDialogWindow window, FrameworkElement dialogContent, IDialogAware viewModel, bool isOrphan)
{
// ...other code.
if (isOrphan)
return;
if (window.Owner == null)
window.Owner = System.Windows.Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);
}
}
If you are done, you have to overwrite the registration for the old dialog service.
containerRegistry.RegisterSingleton <CustomDialogService>();
containerRegistry.Register<IDialogService, CustomDialogService>();
containerRegistry.Register<ICustomDialogService, CustomDialogService>();
Now you can resolve the ICustomDialogService and use its ShowOrphan method to show the window.

Open a copy of the same window using WPF

I am working with a WPF application.I have two text boxes and a button in my first window.Based on some DB operations i need to open the copy of the first window(if possible open like a new tab) provided both windows can be accessed simultaneously.I used
var MainWindow = new MainWindow();
MainWindow.ShowDialog();
and
var MainWindow = new MainWindow();
MainWindow.Show();
both of them doesnt meet my expectations.Can anyone help me.
When you use ShowDialog(), it opens a single modal dialog that is expected to be closed when complete.
If you want to open multiple windows and not block form control, try using Show() instead.
var window = new MainWindow();
window.Show();
I would advise you to read all of the relating pages on MSDN so that you can learn how everything works.
For the Show method:
Opens a window and returns without waiting for the newly opened window to close.
For the ShowDialog method:
Opens a window and returns only when the newly opened window is closed.
From the Remarks section of the Window.Show Method page:
When the Window class is instantiated, it is not visible by default. Show shows a window and returns immediately, without waiting for the window to be closed. Consequently, the opened window does not prevent users from interacting with other windows in the application. This type of window is called a modeless window. Common examples of modeless windows are properties windows, toolboxes, and palettes. To restrict a user to interacting with a specific window, the window must be opened by calling ShowDialog.
Calling Show achieves the same end result as setting Visibility property of the Window object to Visible. However, there is a difference between the two from a timing perspective.
Therefore, for your solution, I would recommend that you use the Show method instead.

Prevent ShowDialog from closing the window in WPF

I have a WPF window myWindow, which I open using myWindow.ShowDialog() ?? true and listen to the DialogResult (DialogResult = true) to execute some code.
When I set it to either true or false, the window is disposed, is there a way I can prevent this window from closing while also getting the DialogResult? Also, is there a another way I can approach this problem?
What do you want to happen? For example:
You might want a modal dialog (so users can't interact with the rest of the UI while it is visible) but you want code to run in the main program in response to some user action in the dialog. In this case, add events to your dialog that the main program can respond to.
Or you might actually want a modeless dialog, which lets users interact with the rest of the program without completing the dialog. In this case, don't use ShowWindow, just show an owned window.

WPF Modal dialog closing ends application unexpectedly

I have a problem with my Application ending unexpectedly when a modal dialog, spawned from the main program window, closes normally. No unhandled exceptions are being thrown and none of the Closing or Closed events are fired on the Main application window.
Essentially I have a main/shell window, which is started in the Application code using ShellWindow.Show(). Through a menu the user can spawn a custom open dialog, this is a new window created and then shown using ShowDialog (the windows owner is set to that of the shell window).
When the dialog is closed (internally, by a command invoking _modalDialogWindow.Close()) the application closes, whereas I would only have expected the modal dialog to have closed.
Debugging the code indicates that the ShellWindow is dumped from memory, as the next executed line of code after _modalDialogWindow.Close() is it falling out of Application.Run() in the static program code.
If anyone has any ideas I am willing to try anything.
It appears that, due to the MVVM/Ioc way I am designing the application window close events are being propagated further than they should. I don't understand this!
However, setting the Application.ShutDownMode to Explicit prevents the app from closing prematurely and I now have the desired behaviour.
Incidentally, turning on all the exceptions as suggested by declyclone didn't yield any exceptions that are thrown internally when then window is closed.
Don't create any windows before you create your application, or they won't get registered properly. They won't show up in Application.Current.Windows or Application.Current.MainWindow. Then when you create your dialog window, your application will think that it is both the MainWindow and the only window.
Example of what not to do:
public partial class App : Application, ISingleInstanceApp
{
MyWindow win = new MyWindow(); //BAD! this is called inside new App(), but before the actual App constructor.
[STAThread]
public static void Main()
{
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
{
var application = new App();
application.InitializeComponent();
application.Run();
// Allow single instance code to perform cleanup operations
SingleInstance<App>.Cleanup();
}
}
I had this problem too, your answer helped me figure out why.

How do I kill a Windows Mobile 6.1 forms app process when the form is closed?

In the Program.cs file of the .Net CF 3.5 WinForms program I've written, I launch the app by instantiating a new instance of Form1.
Application.Run(new Form1());
When I want to close/exit the application, I override the Form1 FormClosed event so that I can ensure exiting the application.
// In Form1 code-behind
private void OnFormClosed(object sender, EventArgs e)
{
Application.Exit(); // Doesn't kill process
}
When this code runs, I want the app to disappear from the screen (close) and I want the process it was running as to die. The app closes (disappears), but unfortunately, the process (we'll call it app.exe) is still running indefinitely. When I start the app again and close it, it spins up another app.exe process, etc. So the process is never dying and more are being created eating memory.
How can I ensure this process is being killed when I close/exit the app? Thanks.
First, you should not have to overide OnFormClosed to get the behavior you're after. Just closing the Form passed in to Application.Run will cause the app's message pump to exit and should cause the process to end. For Windows Mobile you should set the ShowMinimize property of the Form to false to prevent it from just being minimized - you should have a (OK) in the upper right, not an (X).
If the process does not exit when this Form closes, then the culprit 99.99% of the time is that you have a worker thread that is still running preventing the process from closing. Make sure all of your Threads have IsBackground set to true (for CF 3.5) and as a precaution, all of your threads should also have some form of exit notification or flag. Don't rely of the process terminating to tear them down for you.
Your problem is that you have Form.MinimizeBox = true. Change it to false and the form will be closed when ok is clicked instead of minimized when x is clicked.
There are more things to consider in your question:
I override the Form1 FormClosed event
There is no FormClosed event for forms of type System.Windows.Forms.Form, only Closing and Closed.
You don't override an event. You override a virtual function from a base class or interface.

Resources