I'm trying to close my Main Window from a child window in my WPF application. The problem is, once I try to 'close' the main window, my whole application closes.
Here is my coding from my main window(pgLogin):
Window nextWindow = null;
nextWindow = new pgDashboard();
nextWindow.Owner = this;
this.Hide();
nextWindow.Show();
And my child window(pgDashboard):
public static T IsWindowOpen<T>(string name = null) where T : Window
{
var windows = Application.Current.Windows.OfType<T>();
return string.IsNullOrEmpty(name) ? windows.FirstOrDefault() : windows.FirstOrDefault(w => w.Name.Equals(name));
}
private void HAZEDashboard_Loaded(object sender, RoutedEventArgs e)
{
var credentials = this.Owner as pgLogin;
credentials.txtEmailAddress.Text.ToString();
var window = IsWindowOpen<pgLogin>();
if (window != null)
{
window.Close();
}
}
Is there a way to close the main window without hiding it and still keeping open my child window?
Goto to the Applications App.xaml and Change the "ShutdownMode", for example to "OnExplicitShutdown".
The default is ShutdownMode="OnMainWindowClose" which results in the behaviour you described.
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;
When closing my main window(pgLogin) from a child window(pgDashboard), my child window does not want to display at all. In my previous question I set the "ShutdownMode" to "OnExplicitShutdown", so that when I close my main window, the whole application does not shut down. Only thing now is that my application does not shut down, but my child window does not display at all.
Here is my coding from my main window(pgLogin):
Window nextWindow = null;
nextWindow = new pgDashboard();
nextWindow.Owner = this;
this.Hide();
nextWindow.Show();
And my child window(pgDashboard):
public static T IsWindowOpen<T>(string name = null) where T : Window
{
var windows = Application.Current.Windows.OfType<T>();
return string.IsNullOrEmpty(name) ? windows.FirstOrDefault() : windows.FirstOrDefault(w => w.Name.Equals(name));
}
private void HAZEDashboard_Loaded(object sender, RoutedEventArgs e)
{
var credentials = this.Owner as pgLogin;
credentials.txtEmailAddress.Text.ToString();
var window = IsWindowOpen<pgLogin>();
if (window != null)
{
window.Close();
}
}
Any idea why this could be happening?
EDIT: Just did a test, and I can see that when I close the main window, my child window also closes for some reason, because when I try to call this.Show(); on my child window, it gives me this error:
Cannot set Visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after a Window has closed.
EDIT 2: I think the problem might be caused because I set the main window(pgLogin) as the owner of the child window(pgDashboard)?
I figured it out. This is what I did:
My main window(pgLogin):
Window nextWindow = null;
nextWindow = new pgDashboard();
App.Current.MainWindow = nextWindow;
nextWindow.Show();
My child window(pgDashboard):
public static T IsWindowOpen<T>(string name = null) where T : Window
{
var windows = Application.Current.Windows.OfType<T>();
return string.IsNullOrEmpty(name) ? windows.FirstOrDefault() : windows.FirstOrDefault(w => w.Name.Equals(name));
}
private void HAZEDashboard_Loaded(object sender, RoutedEventArgs e)
{
var window = IsWindowOpen<pgLogin>();
if (window != null)
{
var credentials = window.txtEmailAddress.Text.ToString();
window.Close();
}
}
I did not set the owner of the child window(pgDashboard) to pgLogin, because when I close the main window (pgLogin), all of the windows that the main window owns, closes as well.
I'm setting up a simple WPF application, which looks at its command-line arguments to determine what kind of window should be shown next. When that's determined, I show the next window by calling new ApplicationWindow(), set the content, and call Show(). The problem is that the MainWindow instance seems to have "application control" - i.e. when it closes, so does everything else.
It goes like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TopBar.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF1975DD"));
this.ContentRendered += MainWindow_ContentRendered;
this.OperationModeSet += MainWindow_OperationModeSet;
}
[STAThread]
private void MainWindow_ContentRendered(object sender, EventArgs e)
{
Thread worker = new Thread(new ThreadStart(this.ParseCommandLineArgs));
worker.SetApartmentState(ApartmentState.STA);
worker.Start();
}
[STAThread]
public void ParseCommandLineArgs()
{
Thread.Sleep(3000);
string[] args = Environment.GetCommandLineArgs();
if (args.Any(item => item == "--server" || item == "-s"))
{
SetOperationMode(OperationMode.Server);
Dispatcher.BeginInvoke(new Action(delegate()
{
this.CloseWindow();
}));
}
else
{
SetOperationMode(OperationMode.Client);
Dispatcher.BeginInvoke(new Action(delegate()
{
this.CloseWindow();
}));
}
}
[STAThread]
private void SetOperationMode(OperationMode mode)
{
OperatingMode = mode;
if (OperationModeSet != null)
{
OperationModeSet(this, new OperationModeSetEventArgs(mode));
}
}
[STAThread]
private void MainWindow_OperationModeSet(object sender, OperationModeSetEventArgs e)
{
AppWindow window = new AppWindow();
if (e.Mode == OperationMode.Client)
{
this.CloseWindow();
window.Content = new ClientPage();
}
else if (e.Mode == OperationMode.Server)
{
this.CloseWindow();
window.Content = new ServerPage();
}
window.Show();
}
}
These methods get called in the order I've put them here, through various events. I've omitted a few fields and properties.
The problem is that when this MainWindow closes, so does window - the instantiated ApplicationWindow. I assume this is because the MainWindow created it.
However, I do want to be able to close the MainWindow and continue with another window as the "main" window - so how can I decouple the instantiated ApplicationWindow from its parent MainWindow so it continues on?
I've seen setting Application.MainWindow in App.xaml changes the main window - but I have no reference to the instantiated window that I can put into a static XAML file.
Why are you parsing the command line args in your MainWindow?
You could just remove the StartupUri in the App.xaml and override the OnStartup method. Then you can use StartUpArgs to decide which operating mode you want.
In App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
// Decide which window to show here
// Add bounds checks etc.
if (e.Args[0] == "-s")
{
var window = new ServerPage();
window.Show();
}
else
{
var window = new ClientPage();
window.Show();
}
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
base.OnStartup(e);
}
What I think you could do (now there are better options I'm sure...) is instead of creating a new window in your main program, move your other code into a new project and in your main project, launch it as a new process with Process.Start(...).
I've only ever seen code that used this though, never written it from scratch myself. But I would take a look at this page from the MDSN and pages related to it.
Excuse the lack of example code to help you, this is just at the edge of my knowledge and I'd hate to give you incorrect code.
I know there are lots of article over Google related to this, and believe me I have tried almost everything.
So the problem is, I have a wpf application in which when user focuses on any input control like textbox I am showing external touch keyboard using TabTip.exe.
Following code:
public class KeyboardHelper
{
private const string PROCESS_NAME = "TabTip";
private const string PROCESS_PATH = "Common Files/Microsoft Shared/ink/TabTip.exe";
public static void ShowKeyboard()
{
Process keyboard = null;
Process[] pname = Process.GetProcessesByName(PROCESS_NAME);
if (pname.Length == 0)
{
keyboard = new Process();
}
else
{
keyboard = pname[0];
}
string processPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), PROCESS_PATH);
keyboard.StartInfo.FileName = processPath;
keyboard.Start();
}
public static void Closekeyboard()
{
Process[] pname = Process.GetProcessesByName(PROCESS_NAME);
if (pname.Length > 0)
{
pname[0].Kill();
}
}
}
Now problem starts here keyboard open but if it is in docked mode, it causes my app to resize almost half of the screen. And when I close the keyboard app remains same in size, I want to restore to full screen state again.
Controlling my size from cs because it comes from a DB
WindowState = maximized;
ResizeMode= NoResize;
WindowsStyle = None;
Any work around to solve the issue.
I have tried UpdateLayout, Dispatcher.BeginInvoke, Invalidate methods.
Thanks Jason, now I know the cause or can say case scenario of the problem. In my app I have to decide the startup page at runtime, So I am using code like this
private void Application_Startup(object sender, StartupEventArgs e)
{
//Set startup page for the application.
MainWindow window = new MainWindow();
window.ShowDialog();
}
And this is the problem. If I use normal default way than everything works fine.
I have a custom windows modal form with the following event code:
private void btnCancel_Click(object sender, EventArgs e)
{
Close();
_result = DialogResult.OK;
}
The problem is when I click OK, that triggers some process-intensive stuff (report generation) and the form becomes partially drawn on the screen. It's like the report generation is taking precedence over the window refresh. Is there something else I need to do in order to get it to disappear before the process-intensive code? This will most definitely annoy my users.
EDIT #1:
I'm trying to work Tergiver's method and pass in the dialog owner to ShowDialog. For my case, the calling method is not a form. So, I'm trying to create a IWin32Owner from the process's main window handle so that I can pass it into the ShowDialog method.
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
// In calling method
ShowDialog(new WindowWrapper(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle));
However, the dialog owner is still not set after the call to ShowDialog. I stepped into the WindowWrapper and the handle is non-zero. Any more ideas as to how to get the current process's active form?
EDIT #2
I'm now using the following code to retrieve the active form and then calling Owner.Refresh() in the OnFormClosed event.
public static Form GetActiveForm()
{
// Returns null for an MDI app
Form activeForm = Form.ActiveForm;
if (activeForm == null)
{
FormCollection openForms = Application.OpenForms;
for (int i= 0; i < openForms.Count && activeForm == null; ++i)
{
Form openForm = openForms[i];
if (openForm.IsMdiContainer)
{
activeForm = openForm.ActiveMdiChild;
}
}
}
return activeForm;
}
// In code opening dialog.
ShowDialog(GetActiveForm());
The obvious answer is not to do process-intensive code on the UI thread.
Use a BackgroundWorker or the ThreadPool to do the task.
Added
If you insist on doing it on the UI thread, you could use this.Owner.BeginInvoke to execute code after this closes.