Prevent a process from displaying a window during startup - c#

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?

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.

White Screen Appearing When using ShowDialog method Of WPF Window after Hiding

I am developing an Add-in for Autodesk Revit, I have created a WPF Window using XAML and C# as shown in image 1. User of my add-in needs to switch between my Window and Revit and my window needs to maintain its state.
Being it is a modal dialog user cannot interact with Revit until my window is opened. So, in this situation I use Hide instead of close window. And when the user needs it again the add-in uses ShowDialog to display the window again.
But the problem is when I show the window again, it appears white washed (no controls are visible) as shown in image 2. And as soon as I resize my window, all the controls appear back and window starts working normally.
Image 1:
Image 2:
public partial class NavigationWindow : Window, INotifyPropertyChanged
{
...
}
using this code to show,
NavigationWindow navigationWindow = new NavigationWindow();
navigationWindow.ShowDialog ();
To Hide Window, I am using,
Application.Current.Dispatcher.Invoke (() =>
{
this.Visibility = System.Windows.Visibility.Hidden;
});
Any ideas on how can this be fixed?
I would recommend to go with a modeless window instead. This is the proper way to keep the window up while interacting with Revit. The way to go about this is to use the IdleEvent or ExternalEvent. Here's a simple scenario with an idle event. Just switch the window.ShowDialog() to window.Show() that will make it modeless.
First you need to add an idle event queue and handler to the IExternalApplication so something like this:
public class AppCommand : IExternalApplication
{
private static Queue<Action<UIApplication>> Tasks;
public Result OnStartup(UIControlledApplication application)
{
Tasks = new Queue<Action<UIApplication>>();
application.Idling += OnIdling;
return Result.Succeeded;
}
private static void OnIdling(object sender, IdlingEventArgs e)
{
var app = (UIApplication)sender;
lock (Tasks)
{
if (Tasks.Count <= 0) return;
var task = Tasks.Dequeue();
task(app);
}
}
public static void EnqueueTask(Action<UIApplication> task)
{
lock (Tasks)
{
Tasks.Enqueue(task);
}
}
}
So, Idling event is going to fire when Revit is not doing anything. That's a perfect time to interact with Revit from another thread (UI). So when you are in a modless dialog and want to send a task to Revit, you can just use the EnquuqTask utility to put a task into a queue and then Revit when it's not busy will fire Idling event, dequeue the task and execute it. This guarantees that you are not executing anything outside of Revit's scope, and will let you keep the window in modeless state allowing for interaction with Revit while the window is open.
Here's how to add a task to queue from anywhere:
EnqueueTask(app =>
{
//do something
//use app object to interact with Revit
});

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.

How can I create an application in WPF that runs in background

My aim is to place my application in the tray bar but I don't know how to do that for a WPF application ! (for a winform there is lots of docs but I don't find anything for Wpf)
Thanks
You could use this library for the tray icon, and to not have any windows you should remove any StartupUri that may be defined in the App class by default. Then you can override OnStartup to prepare any logic that your application should perform.
Not sure if you can assign a TaskbarIcon of this library directly to the application since it is normally used on Windows. But you can create a dummy popup to make it show up.
public TaskbarIcon MyTaskbarIcon { get; set; }
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Popup pu = new Popup();
pu.Child = MyTaskbarIcon;
//...
}
If you can have windows you can create a TaskbarIcon there and then you can call Hide() if you need it to completely disappear.
After testing it, I recommand http://possemeeg.wordpress.com/2007/09/06/minimize-to-tray-icon-in-wpf/
But be sure your icon is an an “Embedded Ressource” not “Ressource” in properties in Visual Studio.

Where to add a notify icon in a multiple form based application c#

I am making a multiple form based application and have encountered a problem with a notify icon. I have added the notify icon to the first (main) form the user sees but I quickly encountered a problem when the user navigates away from this form and then back to it where a new notify icon is added to the task bar. The way around this i have found is to call ShowDialog() on forms loaded from the main menu and then just Ilosing these forms when the user navigates back. Is this really the only way to do this? I have a very deep application with multiple forms deep do I always have to keep the first form in memory and on screen to maintain the notify icon and ensure new notify icons are not added to the taskbar?
Thanks
As with other WinForms components, this one doesn't need to be placed in a form to work correctly. You can instantiate it, set properties and bind events on another class that isn't a Form. For example, this is a class that could manage a NI control:
namespace WinformsTesting {
using System;
using System.Windows.Forms;
using System.Drawing;
public class NotifyIconManager {
private NotifyIcon _ni;
public void Init() {
_ni = new NotifyIcon();
_ni.MouseDoubleClick += new MouseEventHandler(_ni_MouseDoubleClick);
_ni.Text = "This is my notify icon";
Icon icon = new Icon(#"C:\temp\myicon.ico");
_ni.Icon = icon;
_ni.Visible = true;
}
void _ni_MouseDoubleClick(object sender, MouseEventArgs e) {
MessageBox.Show("Hello");
}
}
}
The only problem here is interaction with the rest of your application, but depending on how you're using the NI control this might be a good starting point.
I would keep a dictionary-type collection at a level higher than your form. Keys would be formId/reference and bool for whether the notify icon was showing or not. Before I would show the notifyIcon, I'd check to see if the Form already has one showing. I'd also register events for the notifyIcon so that when it closes, if changes the dictionary value.
Just an idea to get you started.

Categories