C# & XAML Popup doesn't show in screenshot - c#

I have many popups in a custom GUI application. These popups are window objects, not popup objects. The popups do not show up in a screenshot when using the Print Screen button on the keyboard. Instead, the disabled mainwindow below is all that shows in the screenshot. The popup never flickers or disappears, it just doesn't show in the screenshot.
WindowInstance.IsEnabled = true;
WindowInstance.Refresh();
DisplayPopUpWindow(WindowInstance);
The code in DisplayPopupWindow:
private void DisplayPopUpWindow(Window theWindow)
{
if (theWindow != null)
{
if (theWindow is MessagePopup)
{
// Only show one popup at a time (queue is handled elsewhere)
RemovePopUpsCommand.Execute(true, null);
}
ActiveWindow.IsEnabled = false; // main screen disabled
foreach (KeyValuePair<Window, int> aPopup in popUpWindows)
{
if ((aPopup.Key.IsVisible) && (aPopup.Key.Opacity == 1) && (aPopup.Key != theWindow))
{
// if window is a lower priority then disable it
if (aPopup.Value > displayPriority)
aPopup.Key.IsEnabled = false;
}
}
theWindow.Show();
theWindow.Opacity = 1;
}
}
Is there some property in the XAML that affects whether the window is visible for screenshots? This is a large issue as this also affects some remoting software we use in that popups do not display on the shared screen. Also affects our combobox implementation.
The "popups" are actually their own standalone windows. Some have instances created once during application startup and simply shown/hidden when needed, however, most are created on demand to be displayed. This problem affects both types.
The remoting software used is axeda access remote.

If I remember correctly I had the same problem and I think it was related to setting the popup windows parent to the main window that fixed it, I'd have to look at my code at home to confirm.
So make sure this is correctly set.
EDIT:
Try using this code when you create the Window object:
MainWindowVariable.Owner = Window.GetWindow(this)
You can read more here:
http://msdn.microsoft.com/en-us/library/system.windows.window.owner(v=vs.110).aspx

Related

C# Topmost=true - restrict to application

Our Application is displaying an "update-hint", if a new version is available.
This Update-hint should be "topmost" within the application, but, if the application is minimized, or send to the background, the update-hint should vanish as well..
Just using
this.TopMost = true;
will overlay "ANY" application that is currently running...
Is there a way to just "overlay" windows generated by the current application?
Desired:
application shows update-hint on top of every window, while application is in the foreground. Switching to another application will also send the update-hint to the background.
Desired: Update-Hint overlays ANY window of the current application:
Not desired: Update-Hint overlays FOREIGN applications as well:
Despite the name of the property, TopMost is actually your enemy here. To make a "floating form" stay above a main form, without obscuring other applications when they get focus, try it this way:
FormX f = new FormX();
f.Show(this);
"this" in this example, is the main form instance. It means the form you created is now owned by the main form, and will make it float above it. You get the added benefit of, when minimizing the main form, the floating forms will disappear, too.
I figured out a way to solve it.
Setting the owner of the UpdateHint is required, but in order to keep it on top of every application window, one has to change the owner, if a new Window is either shown, or activated.
Within our application, every Form is inheriting InterceptorForm, so all I had to do was to modify the InterceptorForm accordingly:
Change the Owner to this, except if there is no dialog, or this is the dialog itself:
public class InterceptorForm : Form
{
protected override void OnLoad(EventArgs e)
{
...
if (this.GetType() != typeof(UpdateHint) && MainWindow.updateHint != null)
{
Log.t("Setting owner on update hint during onload: " + this.GetType());
MainWindow.updateHint.Owner = this;
}
base.OnLoad(e);
}
and
protected override void OnActivated(EventArgs e)
{
if (this.GetType() != typeof(UpdateHint) && MainWindow.updateHint != null)
{
Log.t("Setting owner on update hint: " + this.GetType());
MainWindow.updateHint.Owner = this;
}
base.OnActivated(e);
}
}
The UpdateHint now stays on top of every window belonging to our application, but can be overlayed by any other application.

Odd behaviour when opening a WPF Window from WinForms

When displaying a WPF window from an Excel addin, I'm encountering odd behaviour whenever I show it with myWindow.Show() rather than myWindow.ShowDialog(). Thus far everything has worked fine when using the latter. However, it would be nice to be able to display a window such that the user can interact with Excel at the same time - i.e. the behaviour I'd expect from Show().
The problem is that controls in my form start acting very oddly quite quickly. ComboBox dropdowns collapse immediately, and textbox input ends up in whatever cell is selected in the Excel worksheet that's active.
I've noticed that with ShowDialog, Snoop is able to attach to my window as well, whereas with Show, I get an error amounting to "Could not find a PresentationSource to attach to". I'm not, however, completely sure if that's related.
Obviously one solution would be to stop directly showing a WPF window from WinForms; I expect the problem to largely go away if I change my window into a UserControl and chuck it into an ElementHost. However, I'd rather avoid that if I can.
Current code (roughly)
public void DoOpenWindow(Office.IRibbonControl button)
{
var myWindow = new myWindow();
// This hasn't addressed the issue, though may be sensible to include:
//ElementHost.EnableModelessKeyboardInterop(myWindow);
// This *also* didn't work, and essentially set my window to
// be always on top of Excel
//var hwSrc = HwndSource.FromVisual(myWindow );
//var ownerHelper = new WindowInteropHelper(myWindow );
//ownerHelper.Owner = (IntPtr)Globals.ThisAddIn.Application.Hwnd;
// with ShowDialog() this works fine...
myWindow .Show();
}
Current thoughts are:
I'm getting window messages from Excel forwarded to myWindow, some of which it isn't expecting.
Excel is intercepting messages meant for my window (keyboard and mouse), which is probably what ElementHost.EnableModelessKeyboardInterop(myWindow) is intended to solve (but either I'm using it wrong, or it's not the whole solution).

Why can't show FolderBrowserDialog twice in Window constructor?

Out of curiosity, I wonder why I can't show two different instances of FolderBrowserDialog one after the other in the constructor of a Window, but can do it in the Window's Loaded event.
The Example 1 just shows the first dialog (fbd1), and doesn't show the next one.
The Example 2 shows the two dialogs.
Example 1 :
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
using (var fbd1 = new FolderBrowserDialog()) {
fbd1.ShowDialog();
}
using (var fbd2 = new FolderBrowserDialog()) {
fbd2.ShowDialog();
}
}
}
Example 2 :
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
using (var fbd1 = new FolderBrowserDialog()) {
fbd1.ShowDialog();
}
using (var fbd2 = new FolderBrowserDialog()) {
fbd2.ShowDialog();
}
}
}
By the way, I've also tested with WinForms, and this is almost the same.
It doesn't work in the Form's constructor and in the Form's Load event, but works in the Shown event.
The answer you like is not in fact the correct answer, it actually does activate the second dialog. Activation state and Z-order are distinct windows properties. You just can't see the dialog because you lost the foreground. One you can only ever keep when you have a window that can stay in the foreground.
A program gets ~6 seconds to steal the foreground with its own window after it starts up. That timeout is easy to see, Windows displays the Cursors.AppStarting cursor (small arrow with hourglass). That worked to get the 1st dialog into the foreground. What happens next is however doomed to go wrong. When the user closes the dialog then your app has no window left that can be moved into the foreground. Windows now goes hunting for another window to put in the foreground, inevitably one that's owned by another process. Pretty likely to be the VS main window when you debug for example. And the 6 seconds has expired. The 2nd dialog will show up and get activated but of course it is overlapped by that window.
Cold hard fact is that a dialog must always have an owner. FolderBrowserDialog is a bit too forgiving about that, providing you with a ShowDialog() overload without an owner argument. Very convenient, not always correct. It uses GetActiveWindow() under the hood to find an owner. If there isn't one then the desktop window becomes the owner, trouble ahead,
otherwise without throwing an exception.
As Reza Aghaei said in his 2nd comment :
When you close the first dialog, the second one appears, but since
your Form is not visible at the moment and is not visible in task-bar,
it doesn't activate the second dialog, while it's open behind other
windows. Just press Alt+Tab to see open windows and you will see the
second dialog too. But when your Form is visible (for example when run
code in Shown) you will not have this issue.
This is the answer to my curiosity.

Why does hiding and showing a mdi child move the child?

I have a very basic out the box mdiparent which has a number of mdichildren and a menu item. Each button on the menu item hides all the forms and then shows the one respective to that button.
When I do it this way:
//dontHide is the Form we want to show.
for(int i = 0; i < this.MdiChildren.Length; i++)
{
if (this.MdiChildren[i] != dontHide)
{
this.MdiChildren[i].Visible = false;
}
}
dontHide.Visible = true;
Switching forms causes the new form opened to be positioned bit lower and to the right of the old form, but clicking the menu item for the currently displayed form does nothing (as expected).
But, when I do this:
//dontHide is the Form we want to show.
for(int i = 0; i < this.MdiChildren.Length; i++)
{
this.MdiChildren[i].Visible = false;
}
dontHide.Visible = true;
Even clicking the menu item for the currently visible form causes it to shift to the lower right, same as opening a new form. Why is that?
Edit:
I've also noticed when centering the form and then displaying it (so you don't risk having someone glimpse it right before it is moved), setting visible to true completely resets any centering I've done.
This is caused by an obscure implementation detail in Winforms. The native MDI support built into Windows does not support hiding child windows. Winforms works around this restriction by destroying the child window when you set its Visible property to false. And re-creating it when you set it back to true.
This can have various side-effects, the state of the native window is lost when this happens of course. Winforms has fairly decent support for restoring the window again from its properties. But one thing it doesn't do is recreating the window in the same location. So you'll see it getting recreated in the location that new MDI child windows get, staggered from the previous window. Whether that was an oversight or intentional isn't that clear to me, 95% odds for the latter.
Otherwise simple to work around, you can assign the Location property yourself to get it back where it was:
var loc = dontHide.Location;
dontHide.Visible = true;
dontHide.Location = loc;
Or just set the MDI child form's StartPosition to Manual.

Alt keys and tab don't work in Windows Forms opened from a WPF application

I have lots of old Windows Forms applications that will eventually be ported to WPF (it is a large application so it can't be done in one sprint), and I have started the process by creating a main menu in WPF. The Windows Forms applications are separate windows opened from this menu.
The Windows Forms applications are opening and working without any problems except the issues I am having with the shortcut and Tab keys. The tab key is not moving focus to the next control, and the Alt key to trigger the &Search button no longer works.
What am I doing wrong?
A partial solution I discovered is to call this from your WPF constructor:
System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();
(You need to reference the dll WindowsFormsIntegration.dll)
I say partial because not all key strokes function as expected. Eg, seems to work okay for simple forms.
See this:
http://msdn.microsoft.com/en-us/library/system.windows.forms.integration.windowsformshost.enablewindowsformsinterop(v=vs.100).aspx
I finally managed to fix the issue by hosting the winform inside a WindowsFormsHost control inside a WPF form.
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
Form winform = new Form();
// to embed a winform using windowsFormsHost, you need to explicitly
// tell the form it is not the top level control or you will get
// a runtime error.
winform.TopLevel = false;
// hide border because it will already have the WPF window border
winform.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.windowsFormsHost.Child = winform;
}
}
Please note that you may also need to hook up the winform close event if you have a button to close the form.
This is by design. Shortcut keys are handled at the message loop level, detected before the Windows message gets dispatched to the window with the focus. That's the reason those keys can work regardless of the focus.
Problem is, you don't have the Winforms message loop pumping the messages. Application.Run() is implemented by WPF in your program, not Winforms. So any of the code in Winforms that processes keyboard messages to implement shortcut keystrokes won't run.
There's no good solution for this, it is pretty fundamentally the "can't get a little pregnant" problem. This code in Winforms is locked up heavily since it would allow CAS bypass. The only workaround is to display a Form derived class that contain Winforms controls with its ShowDialog() method. That method pumps a modal message loop, the Winforms one, good enough to revive the shortcut keystroke handling code. Restructure your approach by converting the main windows first, dialogs last.
Another solution I found to handle focus on the Tab key is to override OnKeyDown like this:
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
{
HandleFocus(this, ActiveControl);
}
else
{
base.OnKeyDown(e);
}
}
internal static void HandleFocus(Control parent, Control current)
{
Keyboard keyboard = new Keyboard();
// Move to the first control that can receive focus, taking into account
// the possibility that the user pressed <Shift>+<Tab>, in which case we
// need to start at the end and work backwards.
System.Windows.Forms.Control ctl = parent.GetNextControl(current, !keyboard.ShiftKeyDown);
while (null != ctl)
{
if (ctl.Enabled && ctl.CanSelect)
{
ctl.Focus();
break;
}
else
{
ctl = parent.GetNextControl(ctl, !keyboard.ShiftKeyDown);
}
}
}
The advantage of this solution is that it doesn't require neither a WindowsFormsHost nor a message pump which can be a hassle to implement. But I don't know if it is possible to handle shortcuts keys like this because I didn't need it.
Check if IsTabStop="True" and TabIndex is assigned. For Alt + Key shortcut, try using the underscore (_) character instead of the ampersand (&).

Categories