I have a WPF application that has several modal window used for various purposes. This is easily accomplished by using the ShowDialog function. However, in my application I have a timer to measure idle time (i.e. no mouse moves or key strokes) that will cause the user to be logged off. Is there a way (when this timer fires) to find and close all open modal windows without tracking each explicitly?
Update
I would also like to close any MessageBox.Show instances. Is this possible?
Thanks,
Matt
Have you tried to iterate the Application.Current.Windows collection, and close all these that are not the Application.Current.MainWindow?
Jogy
Is there a way (when this timer fires) to find and close all open modal windows without tracking each explicitly?
You could use ComponentDispatcher.IsThreadModal to check to see if you're UI thread is in a modal state. If it is, the Application.Current.Windows property will give you the list of opened Windows.
If you only have a single MainWindow, you could close any others (as they'd be your modal dialogs), but if you have multiple windows, you'd have to check each one.
Unfortunately, there's no direct API to determine whether a specific Window is modal - but there is a private variable in the Window class you could use to do this. For example, the following method uses reflection to determine whether a Window is modal:
public static bool IsModal(Window window)
{
Type type = typeof(Window);
var field = type.GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic);
return field.GetValue(window);
}
This is, unfortunately, subject to change (since it's using undocumented private members).
Related
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
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.
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.
This one has me puzzled, and I am starting to believe it's a bug in either the core winapi, or possibly in WPF. In case nobody here knows a possible cause for the problem I will file a bug report at Microsoft Connect.
The problem presents itself once I call Window.Show(), but the root cause might lie in a different place, including prior calls to user32.dll. Once I call Show() on my window, my window does show up, but another window pops up on the taskbar but doesn't become visible. Moreover, clicking it does not make that window visible.
The window I am trying to show has the following properties set, which seem to be required to cause this weird behavior. Changing any of them 'fixes' this issue.
WindowStyle="None"
WindowState="Maximized"
ShowInTaskbar="False"
I am creating a virtual desktop manager (VDM), hence I hide/show windows through user32.dll. If I don't hide any windows prior to showing my desired window, the problem doesn't present itself either. The entire code of the VDM is available on github. The specific user32 calls occur in a wrapper which can also be found on github.
// Hide windows.
var hideWindows = _windows
.Select( w => new RepositionWindowInfo( w.Info ) { Visible = false } );
WindowManager.RepositionWindows( hideWindows.ToList() );
The RepositionWindows method is a bit long to post here, but you can see it in its entirety on github. It uses BeginDeferWindowPos, DeferWindowPos and EndDeferWindowPos.
Lastly, when I show/hide my window using the Visibility property instead of using Show() and Hide() the described behavior doesn't occur in some circumstances (more on that later) either. However, according to the documentation on msdn:
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. Calling Show is
a synchronous operation that returns only after the Loaded event on
the child window has been raised [...]
This seems very much related to operations being executed synchronously or asynchronously. In some scenarios I hide one particular window using user32's ShowWindow. If immediately after I show my window (using a shortcut key) the problem occurs again, regardless of whether I use Visibility or Show() to show the window. However, if I hide the window using ShowWindowAsync(), all is fine again.
Lastly ... (so many if's ... I know, sorry) when I click on any window (select it) prior to showing my window, the problem doesn't occur either. If I wouldn't be using a shortcut key to show the window I would have never found out about this.
What could be the root cause of this problem?
I think I've identified the core issue which is causing this. When windows are hidden, another window is made active. However, it seems as if only windows present on the task bar are made active. When I hide all windows and afterwards call GetActiveWindow it indicates no window is active (return value null).
When subsequently a window is shown which shouldn't show up on the task bar (no matter whether Show() or Visibility is used) the hidden window is shown on the task bar.
A workaround which fixes this is checking after a deferred window positioning operation whether any window is active. If not, I now give focus to the task bar. Next time the non-taskbar window is shown, the bug doesn't occur!
succeeded = User32.EndDeferWindowPos( windowsPositionInfo );
if ( succeeded && User32.GetActiveWindow() == IntPtr.Zero )
{
WindowInfo startBar = GetWindows()
.Where( w => w.GetClassName() == "Shell_TrayWnd" ).FirstOrDefault();
if ( startBar != null )
{
User32.SwitchToThisWindow( startBar.Handle, false );
}
}
I have a window that I sometimes open using Show() and sometimes using ShowDialog(). In the second case, the returned dialog result is important for me. But if I set the DialogResult after calling Show() I get an InvalidOperationException. Is there a way to find out which method was used to open the window and set or not the DialogResult accordingly? Or is there another way?
Of course I know I can catch and ignore the exception, but I don't like this solution.
Use System.Windows.Interop.ComponentDispatcher.IsThreadModal inside the window to determine if it runs on a modal thread or not.
If you look at set_DialogResult in Reflector, it checks _showingAsDialog to determine whether the dialog is modal. Unfortunately this is a private field.
Do you always construct a new instance of the window before calling Show()/ShowDialog(). If so, you could pass an argument to the constructor indicating how it is to be shown.
You can use the Form.Modal property to check the kind of usage.
In the case of using Form.Show() you have to use another way to let the caller know of any results of the Form.
Is there a reason to use both ways of showing the form?
How about just setting this.DialogResult = DialogResult.blah in the form closing event?