Is there any possibility to make an already shown Window in to a Model Dialog (Like what happens when we call ShowDialog())
Blocking or Non Blocking, Any solution is acceptable for me, but all the Windows in the background should be disabled.
Hiding the window and again showing the window using ShowDialog is not possible since i have to maintain the state.
This is the closest I could get to a solution.The only issue is I change the WindowStyle to remove the title bar because otherwise you can still move those Windows.
this.Topmost = true;
foreach (Window window in Application.Current.Windows)
{
if (window.Title != this.Title)
{
window.Focusable = false;
window.WindowStyle = WindowStyle.None;
window.ResizeMode = ResizeMode.NoResize;
window.IsEnabled = false;
}
}
Related
I have a window with some process and visualization but I want this window to be hidden on startup but still performing it's work. I've managed to achieve this using simple code
SomeWindow.Show();
SomeWindow.Hide();
But the issue is this code causing startup flickering. I can't fight this neither in Windows Forms, nor in WPF. Is there more elegant way to show hidden/invisible window?
UPDATE
I want the window to show in TaskBar but only when it's visible. Window is performing task that relies on rendering that will be performing in time regardless of visibility and user should be able to see it's state like it was open all the time.
Try this:
SomeWindow.ShowInTaskbar = false; // not shown on taskbar set to true if you want to show form on taskbar
SomeWindow.WindowState = FormWindowState.Minimized; // set window state as minimized
SomeWindow.Show();
You don't even need to hide it.
This is winforms version I did not test it in WPF.
Update:
If Hide() is not done after Show() window is on opened windows list (Alt+Tab). To prevent this do:
SomeWindow.Hide();
Based on Logman's answer I've created extension method to show invisible window
For Windows Forms:
public static class FormHelper
{
public static void ShowInvisible(this Form form)
{
// saving original settings
bool needToShowInTaskbar = form.ShowInTaskbar;
FormWindowState initialWindowState = form.WindowState;
// making form invisible
form.ShowInTaskbar = false;
form.WindowState = FormWindowState.Minimized;
// showing and hiding form
form.Show();
form.Hide();
// restoring original settings
form.ShowInTaskbar = needToShowInTaskbar;
form.WindowState = initialWindowState;
}
}
or for WPF:
public static class WindowHelper
{
public static void ShowInvisible(this Window window)
{
// saving original settings
bool needToShowInTaskbar = window.ShowInTaskbar;
WindowState initialWindowState = window.WindowState;
// making window invisible
window.ShowInTaskbar = false;
window.WindowState = WindowState.Minimized;
// showing and hiding window
window.Show();
window.Hide();
// restoring original settings
window.ShowInTaskbar = needToShowInTaskbar;
window.WindowState = initialWindowState;
}
}
Vadim Ovchinnikov's answer for WPF was a great start, but didn't work for me eventually for two reasons: Show() and Hide() are synchronous methods which is a problem when you want to have that window precreated while no other window is open (for there is no Dispatcher executing these requests); furthermore restoring the original values had to be performed later, otherwise a quick flicker was still noticeable. Then again, I had to restore the value of ShowInTaskbar asynchronously; otherwise the taskbar entry was missing, but curiously only when running in the Visual Studio debugger.
The following helper class does the job for me:
public class InitiallyInvisibleWindow
{
private readonly Window _window;
private bool _origShowActivated;
private bool _origShowInTaskbar;
private WindowState _origWindowState;
public InitiallyInvisibleWindow(Window window)
{
_window = window;
}
public void ShowInvisible()
{
_origShowActivated = _window.ShowActivated;
_origShowInTaskbar = _window.ShowInTaskbar;
_origWindowState = _window.WindowState;
_window.ShowActivated = false;
_window.ShowInTaskbar = false;
_window.WindowState = WindowState.Minimized;
_window.Visibility = Visibility.Visible;
_window.Visibility = Visibility.Hidden;
}
public void RestoreVisible()
{
_window.ShowActivated = _origShowActivated;
_window.Visibility = Visibility.Visible;
Dispatcher.CurrentDispatcher.InvokeAsync(() =>
{
_window.ShowInTaskbar = _origShowInTaskbar;
_window.WindowState = _origWindowState;
});
}
}
Why use a window for this task? Why not just start up a class on another thread and have it do the work?
If a window is really needed just have the window when opened request data from that custom task.
var myClass = new MyClass();
Task.Run(()=>myClass.Start());
This works on my machine without "flicker". As Ed mentioned, the Taskbar button behaves as you would expect without addition settings or code.
//Assuming SomeWindow is System.Windows.Form object
SomeWindow.Opacity = 0.0;
SomeWindow.Show();
SomeWindow.Hide();
//Elsewhere in code when you want to display the window
SomeWindow.Opacity = 1.0;
SomeWindow.Visible = true;
I have a WPF Application. I need to minimize and restore the main window after instantiate it to obtain focus. I am using something like the following class but it is not making what I want because when the window is restored it has an invalid size. I've tried to modify the width and height but it is not working.
public class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ConfigureWindow();
}
public void Show()
{
base.Show();
UpdateWindowPositionAndSize();
base.WindowState = WindowState.Normal;
base.Show();
}
private void ConfigureWindow()
{
base.ShowActivated = true;
this.Focusable = true;
if (base.IsActive == false)
{
base.Activate();
}
if (base.IsFocused == false)
{
base.Focus();
}
base.WindowState = WindowState.Minimized;
}
private void UpdateWindowPositionAndSize()
{
this.Top = (SystemParameters.WorkArea.Height - this.Height) / 2;
this.Left = (SystemParameters.WorkArea.Width - this.Width) / 2;
}
}
What I am doing wrong? There is another way to obtain the focus? Sorry if the question is too newby.
UPDATED:
What is the specific need?
I need that my WPF Application appears on focus and active after launch it.
why?
Since it will be launched by a Windows (7, 8.1 and 10) User after explicitly click on a submenu from a file context menu (meaning a Shell Extension). This is 'why' my client wants that appears on front of the screen and focused.
when?
After instantiate the window.
how?
Well, I made some research and I found several ways to do this. One of the methods that I've tried is minimize the window and the restore it. There where others like using the functions SwitchToThisWindow or setforegroundwindow, but I would like to know if there are better options.
What happen when I've tried minimize and restore the window? (correct size)
Well, this way gives me focus on the main window, but it change the width and heigh. By default I define them on 300 (w) and 300 (h), but after changing the windows state to normal these values change to 400 (w) and 350 (h).
If I dont do anything, it has the focus right away?
... No ...
UPDATE2:
I choose the method used in the next link:
https://www.roelvanlisdonk.nl/2014/09/05/reliable-bring-external-process-window-to-foreground-without-c/
I am not quite sure what your problem is but maybe this can help.
1.) Remove StartupUri="MainWindow.xaml" from App.xaml;
2.) Add Startup="Application_Startup"
Your App.xaml.cs should look like this:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
//Create new Instance of MainWindow
MainWindow mainWindow = new MainWindow();
//Set Properties of that Window
UpdateWindowPositionAndSize(mainWindow);
//Show it !
MainWindow = mainWindow; //This is the Application.MainWindow Property - not needed
mainWindow.ShowDialog();
}
private void UpdateWindowPositionAndSize(MainWindow mainWindow)
{
//Do your modifications here
mainWindow.Top = (SystemParameters.WorkArea.Height - mainWindow.Height) / 2;
mainWindow.Left = (SystemParameters.WorkArea.Width - mainWindow.Width) / 2;
}
}
So basically you just modify your Window until all is done.
There is no need to show it first, change its position and then bring it back on - if I got your "usecase" right.
Because to me it looks like you are hiding the window to do your "positioning".
But I think it's better to do it when Initializing.
Just a short comment on your code so far:
ConfigureWindow() is only doing minimize.
The rest of your code is useless cause obviously the window loses focus when it's minimized.
I would suggest not to create methods with names that already exist.
This will only lead to cusfusion.
If you got problems with WindowState = WindowState.Minimized; you can try Hide() and Activate().
By default when calling Window.Show(); the window will have focus. Check here for details.
Also after setting WindowState = WindowState.Minimized; you don't need to call base.Show(); again - the window is shown already. WindowState = WindowState.Normal; should do the job.
I have a modal window that works on desktops with multiple monitors however when I attempt to run the application on a laptop its not overlapping the task bar. Below is the code I'm using to launch it.
if (result != DialogResult.Yes) return;
try
{
using (var fullscreenForm = new fullscreenkForm(eventDetails))
{
fullscreenForm.ShowDialog(this);
}
}
finally
{
Application.Exit();
}
Inside the application I have:
WindowState = Maximized
StartPosition = CenterScreen
AutoSizeMode = GrowOnly
FormBorderStyle = None
TopMost = true
Any help thoughts or help is well appreciated
I apologize if this question has been answered tons of times, but I can't seem to find an answer that works for me. I would like to create a modal window that shows various progress messages while my application performs long running tasks. These tasks are run on a separate thread and I am able to update the text on the progress window at different stages of the process. The cross-thread communication is all working nicely. The problem is that I can't get the window to be on top of only other application windows (not every application on the computer), stay on top, prevent interaction with the parent window, and still allow the work to continue.
Here's what I've tried so far:
First, my splash window is a custom class that extends the Window class and has methods to update the message box. I create a new instance of the splash class early on and Show/Hide it as needed.
In the simplest of cases, I instantiate the window and call .Show() on it:
//from inside my secondary thread
this._splash.Dispatcher.Invoke(new Action(() => this._splash.Show());
//Do things
//update splash text
//Do more things
//close the splash when done
this._splash.Dispatcher.Invoke(new Action(() => this._splash.Hide());
This correctly displays the window and continues running my code to handle the initialization tasks, but it allows me to click on the parent window and bring that to the front.
Next I tried disabling the main window and re-enabling later:
Application.Current.Dispatcher.Invoke(new Action(() => this.MainWindow.IsEnabled = false));
//show splash, do things, etc
Application.Current.Dispatcher.Invoke(new Action(() => this.MainWindow.IsEnabled = true));
This disables all the elements in the window, but I can still click the main window and bring it in front of the splash screen, which is not what I want.
Next I tried using the topmost property on the splash window. This keeps it in front of everything, and in conjunction with setting the main window IsEnabled property I could prevent interaction, but this makes the splash screen appear in front of EVERYTHING, including other applications. I don't want that either. I just want it to be the topmost window within THIS application.
Then I found posts about using .ShowDialog() instead of .Show(). I tried this, and it correctly showed the dialog and did not allow me to click on the parent window, but calling .ShowDialog() makes the program hang waiting for you to close the dialog before it will continue running code. This is obviously, not what I want either. I suppose I could call ShowDialog() on a different thread so that that thread would hang but the thread doing the work would not...is that the recommended method?
I have also considered the possibility of not using a window at all and instead putting a full-sized window element in front of everything else on the page. This would work except that I have other windows I open and I'd like to be able to use the splash screen when those are open too. If I used a window element I would have to re-create it on every window and I wouldn't be able to use my handy UpdateSplashText method in my custom splash class.
So this brings me to the question. What is the right way to handle this?
Thanks for your time and sorry for the long question but details are important :)
You are correct that ShowDialog gives you most of the UI behavior that you want.
It does have the problem that as soon as you call it you block execution though. How could you possibly run some code after you show the form, but define what it should be before it's shown? That's your problem.
You could just do all of the work within the splash class, but that's rather poor practice due to tight coupling.
What you can do is leverage the Loaded event of Window to define code that should run after the window is shown, but where it is defined before you show it.
public static void DoWorkWithModal(Action<IProgress<string>> work)
{
SplashWindow splash = new SplashWindow();
splash.Loaded += (_, args) =>
{
BackgroundWorker worker = new BackgroundWorker();
Progress<string> progress = new Progress<string>(
data => splash.Text = data);
worker.DoWork += (s, workerArgs) => work(progress);
worker.RunWorkerCompleted +=
(s, workerArgs) => splash.Close();
worker.RunWorkerAsync();
};
splash.ShowDialog();
}
Note that this method is designed to encapsulate the boilerplate code here, so that you can pass in any worker method that accepts the progress indicator and it will do that work in a background thread while showing a generic splash screen that has progress indicated from the worker.
This could then be called something like this:
public void Foo()
{
DoWorkWithModal(progress =>
{
Thread.Sleep(5000);//placeholder for real work;
progress.Report("Finished First Task");
Thread.Sleep(5000);//placeholder for real work;
progress.Report("Finished Second Task");
Thread.Sleep(5000);//placeholder for real work;
progress.Report("Finished Third Task");
});
}
The accepted answer from #Servy helped me a lot! And I wanted to share my Version with the async and MVVM approach. It also contains a small delay to avoid "window flickering" for too fast operations.
Dialog Method:
public static async void ShowModal(Func<IProgress<string>, Task> workAsync, string title = null, TimeSpan? waitTimeDialogShow = null)
{
if (!waitTimeDialogShow.HasValue)
{
waitTimeDialogShow = TimeSpan.FromMilliseconds(300);
}
var progressWindow = new ProgressWindow();
progressWindow.Owner = Application.Current.MainWindow;
var viewModel = progressWindow.DataContext as ProgressWindowViewModel;
Progress<string> progress = new Progress<string>(text => viewModel.Text = text);
if(!string.IsNullOrEmpty(title))
{
viewModel.Title = title;
}
var workingTask = workAsync(progress);
progressWindow.Loaded += async (s, e) =>
{
await workingTask;
progressWindow.Close();
};
await Task.Delay((int)waitTimeDialogShow.Value.TotalMilliseconds);
if (!workingTask.IsCompleted && !workingTask.IsFaulted)
{
progressWindow.ShowDialog();
}
}
Usage:
ShowModal(async progress =>
{
await Task.Delay(5000); // Task 1
progress.Report("Finished first task");
await Task.Delay(5000); // Task 2
progress.Report("Finished second task");
});
Thanks again #Servy, saved me a lot of time.
You can use the Visibility property on Window to hide the whole window while the splash screen runs.
XAML
<Window ... Name="window" />
Code
window.Visibility = System.Windows.Visibility.Hidden;
//show splash
//do work
//end splash
window.Visibility = System.Windows.Visibility.Visible;
You can have your progress window's constructor take a Task and then ensure the window calls task.Start on the OnLoaded event. Then you use ShowDialog from the parent form, which will cause the progress window to start the task.
Note you could also call task.Start in the constructor, or in the parent form anywhere before calling ShowDialog. Whichever makes most sense to you.
Another option would be just to use a progress bar in the status strip of the main window, and get rid of the popup. This option seems to be more and more common these days.
I found a way to make this work by calling ShowDialog() on a separate thread. I created my own ShowMe() and HideMe() methods in my dialog class that handle the work. I also capture the Closing event to prevent closing the dialog so I can re-use it.
Here's my code for my splash screen class:
public partial class StartupSplash : Window
{
private Thread _showHideThread;
public StartupSplash()
{
InitializeComponent();
this.Closing += OnCloseDialog;
}
public string Message
{
get
{
return this.lb_progress.Content.ToString();
}
set
{
if (Application.Current.Dispatcher.Thread == System.Threading.Thread.CurrentThread)
this.lb_progress.Content = value;
else
this.lb_progress.Dispatcher.Invoke(new Action(() => this.lb_progress.Content = value));
}
}
public void ShowMe()
{
_showHideThread = new Thread(new ParameterizedThreadStart(doShowHideDialog));
_showHideThread.Start(true);
}
public void HideMe()
{
//_showHideThread.Start(false);
this.doShowHideDialog(false);
}
private void doShowHideDialog(object param)
{
bool show = (bool)param;
if (show)
{
if (Application.Current.Dispatcher.Thread == System.Threading.Thread.CurrentThread)
this.ShowDialog();
else
Application.Current.Dispatcher.Invoke(new Action(() => this.ShowDialog()));
}
else
{
if (Application.Current.Dispatcher.Thread == System.Threading.Thread.CurrentThread)
this.Close();
else
Application.Current.Dispatcher.Invoke(new Action(() => this.Close()));
}
}
private void OnCloseDialog(object sender, CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
}
I have an application that has can display a window using a Form. The form is only shown if the application is run using a -debug flag, otherwise it is only shown in tray.
var form = new Form();
if(DebugMode)
form.Show();
The application listens to CloseMainWindow() when run in debug mode, as the form is shown.
How can I make the application also listen to CloseMainWindow() without showing it? I don't want the user to be able to interact with the form if not in debug mode.
I've tried several approaches, like displaying the window but setting the size to 0. This shows a small form, i.e. not hidden.
if (!DebugMode)
{
form.Show();
form.Size = new Size(0, 0);
}
Also showing it, and then hiding it does not work:
if (!DebugMode)
{
form.Show();
form.Hide();
}
Showing it, but started minimized and not shown in taskbar does not work either:
if (!DebugMode)
{
form.Show();
form.WindowState = FormWindowState.Minimized;
form.ShowInTaskbar = false;
}
Am I missing something really obvious here, or is it not possible to close processes minimized to tray in a graceful way?
If i've understood the problem correctly, you want to completely hide the form when not in debug mode (i.e. the window is not seen anywhere but in the task manager) and when someone kills the process via task manager, you want to execute some code for clean-up or just get notified.
Basing my solution on this assumption, the following code should work
public static bool DebugMode = false;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form1();
form.Load += (s, e) =>
{
if (!DebugMode)
{
form.Opacity = 0;
form.ShowInTaskbar = false;
}
};
form.FormClosing += (s, e) =>
{
// Breakpoint hits
};
Application.Run(form);
}
I'm not sure you can do it through Process.CloseMainWindow(). Processes with no visible main window, I seem to recall, have MainWindowHandle set to IntPtr.Zero.
You need some kind of workaround. My advice is to keep track manually of the MainWindow Handles yourself:
static void Main()
{
...
MainWindow mainWindow = new MainWindow();
[HandleRepository] = mainWindow.Handle;
Application.Run(mainWindow);
}
Then when you want to close the process, do it with a workaround:
public void EndProcess()
{
Form mainWindow= (MainWindow)Form.FromHandle([HandleRepository]);
mainWindow.Close();
}
Might not be the most elegant solution but it should work (haven't tested it)