Dialog appears behind other windows - wpf

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.

Related

Intercept Deactivation Strategy of a Closing window?

I'm using the latest version of Caliburn Micro (4.0.173) in an application leveraging IoC.
I do not have a sample project yet has my sandbox is using nugets from Telerik that are not easily findable. But I think a detailed explanation can get the point across:
I have a ProfileEditorViewModel : Conductor<IScreen>.Collection.OneActive resolved by the container (singleton) through the constructor of my ShellViewModel and I use the I use the WindowsManager to open my ProfileEditorViewModel in a different window:
public class ShellViewModel : IShellViewModel{
private readonly IProfileEditorViewModel _profileEditor;
private readonly IWindowManager _windowManager;
public ShellViewModel(IWindowManager windowManager, IProfileEditorViewModel profileEditor){
_windowManager = windowManager;
_profileEditor = profileEditor;
}
//Method triggered by an Action from the View
public void OpenProfileEditor(){
_windowManager.ShowWindowAsync(_profileEditor, null, null);
}
}
When I close the ProfileEditor window (clicking on the top right red cross), it triggers a closing type deactivation, which is coherent with the implementation of a conductor (not being conducted itself) being shutdown. The Screens collection is being wiped and some more cleaning is being done through the Screen.cs implementation of Caliburn.
However, for this application, I'm facing "the view not being unbound" issue (https://github.com/Caliburn-Micro/Caliburn.Micro/issues/361) and next time I open the ProfileEditor, it'll bind a new view (because the Views Collection of my viewmodel was empty) and it create some issue related to UI components used in the view (basically one event from the viewmodel triggers similar actions, on the view(s) side, that all come back to the viewmodel, which create some identification issue)
Reading through the issue 361, I'm currently able to catch the Unloaded event of my ProfileEditor (once closed), and basically clean the DataContext of any view associated to the viewmodel (before Screen cleans the Screens collections). Next time I open the ProfileEditor, it'll bind a new view and it'll be the only one = it works.
However clearing the DataContext may produce some other issue down the road.
What I would like to do, is to avoid clearing the View collection of the ProfileEditorViewModel upon closing. So Caliburn can use this reference the next time it needs to resolve a window/view for the ProfileEditorViewModel (instead of looking for a new one).
Is it possible to intercept the Deactivation / Closing strategy and change the close parameter to false ?
Another solution may be for my ShellView to be a Conductor<>.Collection.AllActive but I can't wrap my head around teh management of a window closing. How to intercept the ProfileEditor windows closing and proceeding with a deactivation of the ProfileEditorViewModel instead of a closing.
I hope it make sense :)
Thank you in advance for your help

Starting a WPF application as hidden

I'm writing a WPF application and want it to start as a hidden window. I've created the Window object and set its Visibility property to Visibility.Hidden before calling Application.Run(). Then, I have an event handler for Window.Loaded that also sets the visibility to Visibility.Hidden. Between the call to Application.Run() and the callback to OnWindowLoaded(), there is a black outline of the window that flashes up on the screen and then disappears. It's like the window manager is creating a drop shadow for the window or something and then hides it immediately.
After running my project through instrumentation, I finally found that Window.Show() was somehow getting called. So, I looked into the source code at http://www.dotnetframework.org/Search.aspx:
Application.Run() ends up calling a private method named Application.RunInternal().
RunInternal() checks the visibility of the Window object that was passed in to the Run() method.
If the Visibility property is not Visibility.Visible, a call to Window.Show() is made.
I then looked at the source for System.Windows.Window:
Window.Show() sets the Visibility property on itself (the window) to be Visibility.Visible.
Based on this, I don't see how to force the window to stay hidden. By trying to make the window invisible at startup, I'm causing the Application object to call Window.Show(); I don't understand why the Application object even cares about the window's visibility. It's been a frustrating experience... :-(
I've seen other answers that say to not call Application.Run() and to instead set up your own event dispatchers, but that seems like overkill for something that should be easy. I just want the main window to stay hidden, for no "flicker" to appear at app startup, and for the window to become visible when I'm ready for it to do so (which happens later in my application logic).
Can anyone offer a suggestion?
Did you remove the StartupUri entry in App.xaml? If you do, the App class won't instantiate the window for you and show it. You can do this by yourself by overwriting the App.OnStartup method.
Basically, I build a composition root in this OnStartup method and just create a window at the end of the process:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// Do your custom initialization code here
MainWindow = new MainWindow();
MainWindow.Show();
}
If you really want to omit the whole application build up process (which I wouldn't recommend, as you won't have features like the fallback to Application Resources), you can create a Dispatcher by yourself using this code:
var dispatcher = Dispatcher.CurrentDispatcher;
var synchronizationContext = new DispatcherSynchronizationContext(dispatcher);
SynchronizationContext.SetSynchronizationContext(synchronizationContext);
Dispatcher.Run();
The comment on this Answer finally led me to find the solution to this issue. I needed to display multiple windows on multiple screens at once, and by minimizing the window it gives me the performance I needed. Thanks.

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.

Dialog Window for configuration in MVVM

i'm relative new to MVVM. My current problem is a modular dialog which should "autostart" at the beginning.
I've followed the example of WAFs Email Client for modular dialogs. Is it right that the only important thing is to set the Owner Property of the dialog to the instance of the main window of the application (and of course show the window with ShowDialog() instead of Show()?
If you close this dialog without configuration the application will shutdown. But now, if I open the main window in visual studios designer mode the configuration dialog comes up and if I close it visual studio crashes.
This is because I call the ShowDialog() of the configuration dialog in the constructor of my main windows view model.
To avoid this i can check for DesignerProperties.IsInDesignTool Property, but this is more a workaround as good code style, right?
Do you have any suggestions? Thanks.
The problem here is that you are showing a dialog in the constructor of a class. That's something you don't want to do.
I would solve it like this:
Don't specify a StartupUri in your app.xaml but override OnStartup. There you check whether the configuration dialog should be shown or not. If it should be shown, show it and after it has closed with OK, show you main window.
Something like this:
override void OnStartup(...)
{
if(configurationNotComplete)
{
ConfigDialog cfg = new ConfigDialog();
if(!(cfg.ShowDialog() ?? false))
{
Shutdown();
return;
}
}
MainWindow window = new MainWindow();
window.Show();
}
You have another problem with your current approach: Your ViewModel shows a modal dialog. This means it knows at least about one View: That of the modal dialog. MVVM is one way: The View knows about the ViewModel, the ViewModel knows about the Model. There should be no connection in the other direction.

wpf prism composite command

I have a composite WPF application. I am planning to implement tool bar functionality. There are few toolbar items (basically print, save, hide, expand, undo) which will be common to all views in the main region. For this i have created default toolbar module which will add these items (print, save, hide, expand, undo) to the toolbar region. when user clicks any toolbar item, this need to be handled by all 20 views in the main region.
For each toolbar item, i have associated a prism delegatecommand object.
sample:
private ICommand _printCommand;
public ICommand PrintCommand
{
get
{
if (_printCommand == null)
{
_printCommand =
new DelegateCommand<object>(**Print**, **CanPrint**);
}
return _printCommand;
}
}
Xaml, bind toolbar item to this command.
In the main region, we display close to 20 views. All these views have to subscibe to this command. I am thinking of using event aggregator to publish an event, and all the views will subcribe to this event.
For ex:
when the user clicks print, print command executes Print method which will publish print event. This event will be subcribed by 20 views and do further processing.
Am I implementing the toolbar in the right way?
I had initially thought of using composite commands. But by going through documentation it may not fit my requirements.
Ex : Application supports 40 views
Main region -> 20 Views that are active , all the view models are derived from baseviewmodel.
toolbar -> save button -> databinding to compositesaveallcommand(activeaware monitor enabled)
baseviewmodel -> save command -> registers/ unregisters based on specific filter conditions to compositesaveallcommand
when user clicks save button ,compositesaveallcommand looks for all registered commands that are active, and checks for all registered viewmodel commands calls (canexecute method, and all registered commands need to return true) then invokes child commands ( execute method) .
But in my case if the user make modifications in a single view , remaining 19 views there are no modifications. But I would like to execute save for single view. Looks like composite command will not invoke registered comamnds unless it can execute all.
If application allows the user to executes multiple commands at the same time, we may want to allow the user to save all the items on different tabs using a single command represented by a ribbon button. In this case, the Save All command will invoke each of the Save commands implemented by the view model instance for each item.
In the Stock Trader RI, for example, the Submit and Cancel commands for each buy/sell order are registered with the SubmitAllOrders and CancelAllOrders composite commands, as shown in the following code example (see the OrdersController class).
commandProxy.SubmitAllOrdersCommand.RegisterCommand(
orderCompositeViewModel.SubmitCommand );
commandProxy.CancelAllOrdersCommand.RegisterCommand(
orderCompositeViewModel.CancelCommand );
The preceding commandProxy object provides instance access to the Submit and Cancel composite commands, which are defined statically. For more information, see the class file StockTraderRICommands.cs.
public class MyViewModel : NotificationObject
{
private readonly CompositeCommand saveAllCommand;
public ArticleViewModel(INewsFeedService newsFeedService,
IRegionManager regionManager,
IEventAggregator eventAggregator)
{
this.saveAllCommand = new CompositeCommand();
this.saveAllCommand.RegisterCommand(new SaveProductsCommand());
this.saveAllCommand.RegisterCommand(new SaveOrdersCommand());
}
public ICommand SaveAllCommand
{
get { return this.saveAllCommand; }
}
}
This is exactly what the CompositeCommand does. I believe there are no examples (the Commanding QuickStart or the RI do not show active aware activity anymore, they did in Prism v1), but if you use the active aware stuff, you get what you are asking for.
The only thing is that you need to make sure that each of the individual DelegateCommands get their IsActive property correctly updated when they should (i.e. when the view gets activated).
I don't really like the idea of using the EventAggregator too much for things like this. Especially if you decided to create a multi document editor interface, each of your editors is going to be responsible for a lot of filtering to get the events that are only appropriate for them.
It might be easy to use EventAggregator for this purpose, but I think it's probably not really the right fit. That said, it's not really wrong... in fact I believe a few of the Prism samples do exactly this, but I think it puts too much responsibility on the constituents for filtering, rather than leveraging framework features.
Your subject suggests you were thinking of using CompositeCommands for this. Is there any reason you aren't doing this instead of using the EventAggregator? If you had a standard place where ViewModels could register their Commands designed to handle each of these buttons with a composite command sitting behind each one, wouldn't that give you the functionality you wanted? In addition to being able to handle the button commands, each of the constituent views/viewmodels would be able to disable buttons when they were inappropriate, etc.
Take a close look at the CompositeCommand samples in the Prism documentation and see if they don't do what you want.

Resources