WPF Modal dialog goes in background - wpf

I have problem with an application where modal WPF dialog occasionally goes behind the main application window. This hapens when I click button on the dialog which does some processing and updates controls (through binding) in the main application window. When it goes in background - clicking anywhere in the application brings it back into foreground.
var dialog = LoadDialogWindowThroughMEF();
dialog.Owner = Application.Current != null ? Application.Current.MainWindow : null;
dialog.ShowInTaskbar = false;
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
return dialog.ShowDialog();
The above code shows how I open modal window. This happens very rarely.
Does anybody know what could be the problem?

I'm not sure I have an answer for you, but I can share some of my thoughts:
Every time I've encountered this type of problem, it happened because the Owner wasn't set properly. So, I'd try to not set the Owner and see if that makes the problem reproducible. You need to be absolutely sure that Owner is set to the correct parent window at all times1. You might also want to check that it is the actual MainWindow of your application that are supposed to be the parent. I think that most of the time it is beneficial to be explicit2 in your code. In this case that means that it is better to assign the known parent (maybe you have a reference to the parent somewhere that you could use), rather than relying on the Application.Current to provide you with that reference. Doing so will put you in control of the assignment to Owner. It could even make it possible to get rid of the ?: operator since you would have the means to control the reference even during unit testing.
I also want you to make sure that the code that is actually updating the parent window doesn't in any way force focus to a specific control on the parent window, or anything like that. (As long as the correct parent is set as Owner, I don't see this as a likely problem.)
I hope this helps you, but I understand if it doesn't. The fact that your dialog reappears when you click the parent window disproves some (or all!) of my points...
1 Except when running your unit tests, but that's a completely different matter.
2 As in the first meaning of the word according to wiktionary.org/wiki/explicit, and as opposed to implicit.

Related

Wrong window shows up on taskbar when calling `Show()`

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 );
}
}

How to dispose of dynamically loaded usercontrols/viewmodels when parent window is closed

We have a main window that launches a child window. That child window dynamically loads custom usercontrols. In the contructor of these usercontrols, I pass a master object which, from this master object, a usercontrol specific viewmodel is generated and assigned as its datacontext.
All of this is working quite well. However, I jst discovered that when I close the child window at least some of my custom usercontrols are still active. How am I supposed to clean up my controls/viewmodels? Nothing seems to get called until the main window is closed. No destructor, no Dispatcher.ShutdownStarted, no dispose is available, no closing event, nothing I can find.
Anyone know what is supposed to be done to properly clean up after the window is closed?
I believe you need to think precisely about what is responsible for creating your views and your viewmodels, and what is responsible for determining whether or not something can close or not, etc.
It is usually a good idea for whatever that created something to destroy it. Therefore, if your child window is creating custom user controls it perhaps should be responsible for removing them. However, I believe if none of your objects has a reference (or strong event subscription) it should be eventually garbage collected. You could implement a finalizer/destructor and output a Debug.String to the output window to see when this might eventually happen. A good memory profiler could also be a good idea. However, it is also likely that you need more precise control of telling your ViewModel when it has been closed.
It's hard to say exactly what should happen in your scenario because it really depends on your exact and specific setup. Let me describe to you a scenario I had in my application. I had several views that were being displayed in tab pages. The tab pages had an X button to close the tab, and my View contained a hosted Windows Forms control that needed to have .Dispose() called to clean up resources as well as it needed to be informed of when to unsubscribe from composite commands in the file menu system. So, initially, I had a problem... how does my ViewModel unsubscribe from commands when the tab pages remove's the view? How does the View which is contained in a WPF control know when it has been removed? here's what I came up with
The tab page itself should not be telling my program if a view can or can not be closed
I needed the ability to cancel the closing event in case of program logic (File saved? Yes/no/cancel)
I needed the ability to detect when it was closed so I could cleanup/unregister at that exact moment
My solution was to implement an interface in my viewmodel called IRemovable which exposed a Removable boolean and a Remove() method which returns a boolean (was removed or not). My tab control only displayed the X button if Removable was true, Tab Control's Closing fired the Remove() of the IRemovable ViewModel and if it returned false it set the event args Canceled property to true if the ViewModel's Remove returned false.
Therefore, the remove of the view model could prompt the user for confirmation, unregister from commands, etc. The view could handle Closed event and call Dispose on any Windows Forms components etc. (of course I had to check if my View.DataContext is IRemovable).
Anyway, I know this isn't an exact answer but hopefully it helps you come up with some thoughts on how to solve your own problem

WPF: Determine if a Panel is visible to the user

I have a WPF usercontrol (myGraphicControl) in a tab (WPF application).
When the form size changes, I redraw the graph in myGraphicControl.
Since the redrawing operation is a I need to do it only the control in in the visible tab.
How the WPF (user)control can detect if it's "visible" actually or not?
PS.
by Visible I mean that user can see it.
say, if a Visible TextBox is located in the currently invisible tab, this textBox is not visible by the user.
I don't believe there is a quick-fix solution here, but you may be able to do something using UIElement.InputHitTest(Point).
You could make a call similar to
//get the coordinates of the top left corner of the child control within
//the parent
var childTopLeft = childControl.TranslatePoint(new Point(), parentControl);
//check whether or not the child control is returned when you request the element
//at that coordinate through hit testing
var isVisible = (parentControl.InputHitTest(childTopLeft) == childControl);
However, I should point out that I haven't tried this myself, and that it probably won't work in the following scenarios:
Transparent items - generally, transparent backgrounds cause hit testing of a control to pass to the parent
Partially occluded items - you can only hit-test one point at a time, so if only part of your child control is visible you will have to check the correct point
I've found that while Steve's method generally works, it works much more reliably if you get a point from somewhere in the middle of the child control. I'm guessing that maybe layout rounding somewhere along the way makes the InputHitTest check somewhat inexact. So, change his first line to the following and you're golden:
var childTopLeft = childControl.TranslatePoint(new Point(childControl.RenderSize.Width/2, childControl.RenderSize.Height/2), parentControl);
Maybe UIElement.IsVisible will be helpful? It works for tab contents well.
Anyway you can use a solution described here.
I have one more solution. The current implementation of TabControl removes inactive tabs from visual tree. So, another way to determine whether your element is visible is to find PresentationSource. It will be null for elements of inactive tabs.

Main form not shown in Taskbar

What could be the reasons for the Main application form not to be shown in TaskBar?
ShowInTaskbar property is set to "true", but form doesn't show itself there if after running the application and before the Main form appears I switch to some other window. Form exists, but until I minimize apps that are above to make it visible, it won't show in Taskbar.
UPDATE. Form does not have an Owner.
I've added form.Activate() after form.Show(). Now it always jumps out when completely loaded, and doesn't get lost under some other screens.
Though it is not a solution, but a crutch, responses are welcome anyway.
Check if your main form has a Parent defined or an Owner. In either case that would exclude it from being in the task bar in its own right. Also worth trying TopMost=true.
I had the same issue with one project I wrote.
No icon showing in the Taskbar unless I forced Windows to refresh it.
It was a call to
this.MinimumSize = new Size(wid, len);
In the Form_Load that was the issue.
I had a similar issue when the program was run from an installer (InstallMate in my case). I eventually pinned the problem down to changing the form's title text (Text) in the Form1_Load() method. When I moved that title changing text to just below the InitializeComponent(); bit, the problem went away.
I hope this can help someone else, despite the specificness of my circumstances.
I had the same issue as #deegee where setting MinimumSize in the Form Load causing the non display in the Taskbar. I fixed the issue with setting the Form Visible to False then to True.

WPF modal window behaves weird

I 'm running into a situation i don't understand and want somebody to enlighten me if possible.
Created a WPF application. For sake of simplicity consider this application to be one window. I put some controls on this window, amongst others there is a TextBox control (let's call it TB).
There is a requirement that this TB must always have the focus (in case someone types something or something is read through the barcode-scanner it should appear there).
I thought implementing this with the help of a timer: every second the focus is transferred to the TB.
Until now everything works fine (as expected).
The weird thing is the following: let's say a new user wants to use this window, so she has to sign in. I thought implementing this with a new Window object (let's call it W2), calling it this way:
W2.ShowDialog();
This W2 window should be modal (bear in mind that the timer still executes).
The crazy thing is that under Windows Vista this works perfectly as expected (this means W2 is modal and the user can to what she should do on W2), BUT on Windows XP as soon as the user wants to type something in a textbox of W2 the focus is set back to TB on the initial Window (as far as i can interpret: this means W2 is not modal!!!? am i right?).
How can i overcome this situation?
Is this the right approach?
Thanks in advance
Make sure to set the Owner property of W2 to your main Window.
From the referenced docs:
When you open a child window by calling ShowDialog, you should also set the Owner property of the child window.
I am not sure this setting-the-focus-back-every-few-seconds is such a good idea. It is always possible that some input will come in the interval between a lost and got focus state (and be lost). Alternative solutions are catching the PreviewKeydown event on the form that the TB resides on and somehow set the output of a barscanner to the TB too.

Resources