Closing MainWindow hides child window - c#

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.

Related

Window open on Notification click

I have created a chat application, so when I received a message there is a notification generated so that on clicking notification my chat application should open and I did it using this code below
if (!ApplicationContext.ContactsViewModel.IsWindowOpen)
{
ApplicationContext.CurrentChatView.Dispatcher.Invoke(() =>
{
ApplicationContext.CurrentChatView.WindowState = WindowState.Normal;
ApplicationContext.CurrentChatView.Activate();
});
}
so the problem here is my application is performing all the tasks in the background but instead of appearing in the foreground
I have also tried :
ApplicationContext.CurrentChatView.Topmost=true;
but in this case, the application remains topmost even after clicking on another window.
is there any other alternative to it??
thanks in advance
You should make corrections in your method calling order. Try the following:
if (!ApplicationContext.ContactsViewModel.IsWindowOpen)
{
ApplicationContext.CurrentChatView.Dispatcher.Invoke(() =>
{
if (!Window.IsVisible)
{
Window.Show();
}
if (Window.WindowState == WindowState.Minimized)
{
Window.WindowState = WindowState.Normal;
}
Window.Activate();
Window.Topmost = true; // important
Window.Topmost = false; // important
Window.Focus(); // important
});
}
You can use window.Show() / window.Hide() methods to switch between visible and hidden mode:
private void ShowCurrentWindows()
{
foreach (Window window in Application.Current.Windows)
{
if (!window.IsVisible)
{
window.Show();
}
}
}
private void HideCurrentWindows()
{
foreach (Window window in Application.Current.Windows)
{
if (window.IsVisible)
{
window.Hide();
}
}
}

Showing invisible window

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;

How to stop MainWindow from closing whole application

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.

How can I pass application control to another WPF window?

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.

How do I get custom dialog close without showing graphics artifacts?

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.

Categories