C# Topmost=true - restrict to application - c#

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.

Related

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.

Form disappears when resetting Form's TopLevel property

In my application I am displaying a new form which needs to be at TopLevel.
So, I am setting
someForm.TopLevel = true;
Now, I have a checkbox, which will allow user to set it to "not a top level".
When unchecked, i want to set TopLevel = false
But when I do this, my form disappears. Does anyone know why?
Here is my code:
private void stayOnTop_CheckedChanged(object sender, EventArgs e)
{
this.TopLevel = this.stayOnTop.Checked;
}
Because your checkbox is named stayOnTop, I assume you want to set the TopMost property instead of TopLevel.
The setting TopLevel is only meaningful in MDI applications - ones where a parent form has one or more child forms inside it (like Word and Excel used to work).
TopLevelControl is the main form of your application. By setting TopLevel to false the TopLevelControl is set to null. In that case there is no main form to display for your application. If you add a timer that will switch it back to true you will see that it appears again. (It is interesting though that there is no preventing mechanism. For instance it's not possible to add a top level form to another top level form. But you are allowed to get rid of top levels forms entirely.)
So that's why it disappears. If you want it only sent to background you can use SendToBack() method. It will change Z-index of the form. So if there is a window behind your control, the control will be moved behind the window.
Try these codes :
private void stayOnTop_CheckedChanged(object sender, EventArgs e)
{
if(e.checked == true)
{
someForm.TopLevel = false;
}
else
{
someForm.TopLevel = true;
}
}

C# & XAML Popup doesn't show in screenshot

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

Statically located winforms in C#

I have three forms in C#, now when I want to show form2 I hide the main one and show the form and then when done working, hide the second form and show the main form again - I am doing this with the simple hide and show functions in winforms. Now the problem is every called form is placed on a different location on the screen, while I want all of them to stay on the same place. How to do it?
Try setting the owner of the form when you call .Show()
You can also set the start position before you call show with .StartPosition = FormStartPosition.CenterParent
Or set the form.Location property after you call show
See here and here for more details
You no doubt have a bug in your code, you are creating a new instance of the form instead of calling Show() again on the hidden form object. That's a bad kind of bug, it will make your program consume a lot of machine resources, ultimately it will crash when Windows refuses to allow your process to create more windows.
To make your scheme work, you have to write code that distinguishes between a closed form and a hidden one. Best way to do that is to explicitly keep track of its lifetime with the FormClosed event. Like this:
private Form2 form2Instance;
private void button1_Click(object sender, EventArgs e) {
if (form2Instance == null) {
// Doesn't exist yet, so create and show it
form2Instance = new Form2();
form2Instance.FormClosed += delegate { form2Instance = null; };
form2Instance.Show();
}
else {
// Already exists, unhide, restore and activate it
form2Instance.WindowState = FormWindowState.Normal;
form2Instance.Visible = true;
form2Instance.BringToFront();
}
}

Prevent a process from displaying a window during startup

I'm launching an application from a WPF app using the Process class that displays a splash screen at startup. Rather than show the user the splash screen, I'd like to hide the application for the first couple of seconds after starting it by keeping my window topmost and maximized. The problem is that starting this application automatically takes my window out of topmost mode and shows the windows task bar. Is there a way to prevent the process from showing a window for a few second until it starts up, then displaying its window?
So you have two application fighting about being top most window but of course only one can be top most at the same time. Windows rightfully don't let a single application make that decision, that would be a security hole. See Raymond Chen's answer here why: http://blogs.msdn.com/oldnewthing/archive/2005/06/07/426294.aspx
Do you own the application you are trying to start without showing it's main window directly at startup? In that case do the following.
Override the Application.OnStartup method in your App class and do your initialization there. No windows or taskbar buttons will be displayed (automatically) until after that method finishes.
using System.Diagnostics;
using System.Threading;
using System.Windows;
namespace DelayedStartDemo
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
Thread.Sleep(5000);
base.OnStartup(e);
Debug.Assert(MainWindow == null);
}
protected override void OnActivated(System.EventArgs e)
{
Debug.Assert(MainWindow != null &&
MainWindow.Visibility == Visibility.Visible &&
MainWindow.ShowInTaskbar);
base.OnActivated(e);
}
}
}
Can't you just set the visibility of the MainWindow that starts up to Collapsed and then toggle it after the splash launches?

Categories