Instead of using a traditional splash screen, I want to display a login window to allow the user to enter their credentials. Meanwhile, in the background, I want to initialize the app, then load the main window. The problem is that the login window is covered up by the main window once shown.
private void App_OnStartup(object sender, StartupEventArgs e)
{
Current.MainWindow = new LoginWindow();
Current.MainWindow.Show();
Task.Run(() => { /*do app startup background stuff*/ }).ContinueWith(t =>
{
var appWindow = new ApplicationWindow();
appWindow.Show();
Current.MainWindow.Owner = appWindow;
}, TaskScheduler.FromCurrentSynchronizationContext());
The login window is made the main window from the start. My assumption was that by setting the ApplicationWindow's owner to the login window, the login window would remain on top. If I'm doing it wrong, is there a way to achieve what I want? The topmost flag works but then the window is, well, topmost, which is undesirable.
Suppose you have a MainWindow:
<Window x:Class="SO40189046.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SO40189046"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock Name="TimeText" />
</Grid>
</Window>
with code behind:
using System;
using System.Threading;
using System.Windows;
namespace SO40189046
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
// Background thread initializing the MainWindow
ThreadPool.QueueUserWorkItem((state) =>
{
for (int i = 0; i < 10; i++)
{
Dispatcher.Invoke(() =>
{
TimeText.Text = DateTime.Now.ToString();
});
Thread.Sleep(1000);
}
});
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
LoginWindow login = new LoginWindow();
login.Owner = App.Current.MainWindow;
login.WindowStartupLocation = WindowStartupLocation.CenterOwner;
if (!login.ShowDialog().GetValueOrDefault())
{
Close();
}
}
}
}
Then you can initialize your MainWindow while showing the login dialog.
AND you load the MainWindow as normal via StartUpUri in App.xaml
Related
So I have a main windows that loads a page this page is a settings page and I have the setting topmost, because I am using a page to display the buttons I did:
if(TopMostCheckBox.IsChecked == true)
{
MainWindow main = new MainWindow();
main.Topmost = true;
}
if(TopMostCheckBox.IsChecked == false)
{
MainWindow main = new MainWindow();
main.Topmost = false;
}
but for some reason when I load my program I check box doesn't check top most so how can I make my page toggle top most for my main window.
Answering your Question title:
how can I make a topmost checkbox WPF C#
As a Minimal, Reproducible Example the following would apparently work in the MainWindow code-behind of a newly created WPF project:
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<CheckBox Checked="CheckBox_CheckedChanged"
Unchecked="CheckBox_CheckedChanged"/>
</Grid>
</Window>
MainWindow.CS:
using System.Windows;
using System.Windows.Controls;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
Topmost = ((CheckBox)sender).IsChecked == true;
}
}
}
You can do this within the xaml
<Window
.........
Topmost="{Binding ElementName=chkbox, Path=IsChecked}" >
<Grid>
<CheckBox x:Name="chkbox" Content="topmost ?" />
</Grid>
</Window>
You're creating a new instance of mainwindow rather than referencing the existing instance.
if (TopMostCheckBox.IsChecked == true)
{
var main = Application.Current.MainWindow as MainWindow;
main.Topmost = true;
}
The above assumes you've not given mainwindow a different name to the default.
You might find you have to set topmost false and then true to get it to respond.
I have a program when I log in, I have to wait for loading database from server. So I created a "Loading..." window. After loading the database, this will automatically close the "Loading" window, the "Login" window and open the MainWindow.xaml.
But myprogram have a problem: when I use waitForm.show() in Login.xaml.cs, it runs good, but the controls on "Waiting" window like progressbar, textblock, it doesn't display.If I use waitForm.showdialog(), it will display progressbar and textblock control. But it won't automatically close. So my Mainwindow.xaml not open.
Is it possible to use show() but show the controls?
Sorry about my bad English. Thank you.
Waiting.xaml
<Window x:Class="TMO.Waiting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TMO"
mc:Ignorable="d"
Title="Waiting" Height="100" Width="300" WindowStartupLocation="CenterScreen" WindowStyle="None">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ProgressBar Margin="10,20,10,5" Minimum="0" Maximum="100" Name="pbStatus" IsIndeterminate="True" Grid.Row="0"/>
<TextBlock Grid.Row="1" Margin="0,5,0,5" TextAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="Bold" >Loading...</TextBlock>
</Grid>
</Window>
Waiting.xaml.cs
using System.Windows;
namespace TMO
{
/// <summary>
/// Interaction logic for Waiting.xaml
/// </summary>
public partial class Waiting : Window
{
public static MessageBoxResult result;
public Waiting()
{
InitializeComponent();
}
public Waiting(Window parent1)
{
InitializeComponent();
}
public void CloseWaiting()
{
DialogResult = true;
this.Close();
}
}
}
WaitFunc.cs
using System.Threading;
using System.Windows;
namespace TMO
{
public class WaitFunc
{
Waiting wait;
Thread loadthread;
public void show()
{
loadthread = new Thread(new ThreadStart(LoadingProcess));
loadthread.Start();
}
public void show(Window parent)
{
loadthread=new Thread(new ParameterizedThreadStart(LoadingProcess));
loadthread.Start(parent);
}
public void Close()
{
if(wait!=null)
{
wait.Dispatcher.BeginInvoke(new System.Threading.ThreadStart(wait.CloseWaiting));
wait=null;
loadthread=null;
}
}
public void LoadingProcess()
{
wait=new Waiting();
wait.ShowDialog();
}
public void LoadingProcess(object parent)
{
Window parent1 = parent as Window;
wait=new Waiting(parent1);
wait.ShowDialog();
}
}
}
Login.xaml.cs
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
this.Hide();
Waiting waitForm = new Waiting();
waitForm.Show(); //If I use waitForm.showdialog() it will display all control
Thread.Sleep(500);
MainWindow main = new MainWindow(txtUserName.Text);
this.Hide();
waitForm.Close();
main.Show();
this.Close();
}
You should manage all windows of the application launch sequence from the entry point of your application. Therefore, I recommend to move the logic to start the MainWindow from the Login.xaml.cs to the App.xaml.cs.
Furthermore, to create a UI thread that can show controls and allows input handling you must explicitly configure the thread to be a STA thread and additionally start the Dispatcher message loop.
Note, if you use async APIs and background threads when necessary (use Task.Run and not Thread), then you don't need an extra UI thread only to show the splash screen.
You should add a LoginSuccessful and a LoginFailed event to the LoginWindow.
Your flow could be implemented like this:
App.xaml
<Application Startup="App_OnStartup" />
App.xaml.cs
public partial class App : Application
{
private Window SplashScreen { get; set; }
private void App_OnStartup(object sender, StartupEventArgs e)
{
ShutdownMode = ShutdownMode.OnExplicitShutdown;
var loginScreen = new LoginWindow();
loginScreen.LoginSuccessful += RunApplication_OnLoginSuccessful;
loginScreen.LoginFailed += ShutdownApplication_OnLoginFailed;
loginScreen.Show();
}
private void RunApplication_OnLoginSuccessful(object sender, EventArgs e)
{
var newUiThread = new Thread(new ThreadStart(ShowSplashScreen))
{
ApartmentState = ApartmentState.STA,
IsBackground = false,
};
newUiThread.Start();
var mainWindow = new MainWindow();
mainWindow.Loaded += CloseSplashScreen_OnMainWindowLoaded;
mainWindow.Closed += ShutdownApplication_OnMainWindowClosed;
// TODO::Initialize application
mainWindow.Show();
}
private void ShowSplashScreen()
{
this.SplashScreen = new Window() { Content = "SplashScreen" };
this.SplashScreen.Show();
// Start event queue
Dispatcher.Run();
}
private void CloseSplashScreen_OnMainWindowLoaded(object sender, RoutedEventArgs e)
{
this.SplashScreen.Dispatcher.InvokeAsync(() =>
{
this.SplashScreen.Close();
this.SplashScreen.Dispatcher.InvokeShutdown();
});
}
private void ShutdownApplication_OnMainWindowClosed(object sender, EventArgs e) => Shutdown();
private void ShutdownApplication_OnLoginFailed(object sender, EventArgs e) => Shutdown();
I implemented the control basics sample from the Kinect for Windows toolkit http://msdn.microsoft.com/en-us/library/dn188701.aspx to control the cursor with a users hand, but when I click on a sub window and then re open the main window with the hand cursor doesn't show.
My question is how do I open a new window without closing the previous window and then navigate back to the same instance of that window, not a new instance?
This is how I call a new window in my main window class:
private void trainingBtn_Click(object sender, RoutedEventArgs e)
{
var newForm = new TrainingFrm(); //create your new form.
newForm.Show(); //show the new form.
this.Close(); //only if you want to close the current form.
}
And this is how I reopen the main window, but it creates anew instance of the main window which I don't want.
private void homeBtn_Click(object sender, RoutedEventArgs e)
{
var newForm = new MainWindow(); //create your new form.
newForm.Show(); //show the new form.
this.Close(); //only if you want to close the current form.
}
What you need is composition
Here how it should look your mainWindow class
public partial class MainWindow : Window
{
private trainingWindow _trainingWindow;
public MainWindow()
{
InitializeComponent();
}
private void buttonGoTraining_Click(object sender, RoutedEventArgs e)
{
if (_trainingWindow== null)
{
_trainingWindow= new trainingWindow(this);
}
this.Visibility = Visibility.Hidden;
_trainingWindow.Show();
_trainingWindow.Visibility = Visibility.Visible;
this.Visibility = Visibility.Hidden;
}
}
and here is your training class
public partial class trainingWindow : Window
{
private MainWindow _mainWindow;
public trainingWindow(MainWindow mainWindow )
{
InitializeComponent();
_mainWindow = mainWindow;
}
private void biuttonBack_Click(object sender, RoutedEventArgs e)
{
this.Visibility = Visibility.Hidden;
_mainWindow.Visibility = Visibility.Visible;
}
}
here is the xaml
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" Height="121" HorizontalAlignment="Left" Margin="112,38,0,0" Name="button1" VerticalAlignment="Top" Width="195" Click="buttonGoTraining_Click" />
</Grid>
</Window>
<Window x:Class="WpfApplication2.trainingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="trainingWindow" Height="300" Width="300">
<Grid>
<Button Content="Button" Height="36" HorizontalAlignment="Left" Margin="52,33,0,0" Name="button1" VerticalAlignment="Top" Width="97" Click="biuttonBack_Click" />
</Grid>
</Window>
Simply hide it, and not close.
If you need to show a fresh information after show, just bind a new data to its view model.
I want to open the help file to a page based on some custom logic. How can I handle the user pressing F1 on all of my windows (main window and modal dialogs) ?
I know how to handle F1 in a single window, but can this be done globally, so I don't have to add the same code to all of my windows ?
Below is the test with which I've tried out that F1 does not work on the child window.
Window1.xaml:
<Window x:Class="WpfApplication2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Help"
Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<Grid>
<Button Content="Open a new window"
Click="Button_Click"/>
</Grid>
</Window>
Window1.xaml.cs:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication2
{
partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Help");
}
void Button_Click(object sender, RoutedEventArgs e)
{
new Window().ShowDialog();
}
}
}
I've found the answer on this page.
That is, put this in the main window's constructor for example:
CommandManager.RegisterClassCommandBinding(typeof(Window),
new CommandBinding(ApplicationCommands.Help,
(x, y) => MessageBox.Show("Help")));
In a WPF application I would like to implement the following behaviour which doesn't seem to work straightforward:
From the main window (Window1) the user opens a non-modal window (Window2), and that non-modal window may display a modal dialog (Window3).
The problem is that whenever the modal dialog has been shown, the main window disappears in the background (given that there are windows of other applications open) when the user closes the dialogs.
Is there anything wrong in the way that I use Window.Owner and Window.Show()/Window.ShowDialog(), is it a bug or is it something simply not supported?
The following simple WPF application demonstrates this behavior:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window2 win = new Window2();
win.Owner = this;
win.Show();
}
}
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window3 win = new Window3();
win.Owner = this;
win.ShowDialog();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
public partial class Window3 : Window
{
public Window3()
{
InitializeComponent();
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
XAML Window1:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1">
<Button Click="Button_Click">Show non-modal window</Button>
</Window>
XAML Window2:
<Window x:Class="WpfApplication1.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2">
<StackPanel>
<Button Click="Button_Click">Show modal dialog</Button>
<Button Name="btnClose" Click="btnClose_Click">Close</Button>
</StackPanel>
</Window>
XAML Window3:
<Window x:Class="WpfApplication1.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3">
<Button Name="btnClose" Click="btnClose_Click">Close</Button>
</Window>
UPDATE: Fixed copy&paste error in the code. This is .NET 3.5 SP1 in case it matters.
Microsoft confirms this as a bug in WPF:
This isn't a regression from previous releases so it doesn't make the bar to be fixed for this version of the product. We'll look into this for a future release.
In the meantime, this can be worked around by activating the owner window when the child window is closing.
Sample code:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void NonModalButtonClick(object sender, RoutedEventArgs e)
{
new Window1 { Owner = this }.Show();
}
private void ModalButtonClick(object sender, RoutedEventArgs e)
{
new Window1 { Owner = this }.ShowDialog();
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (this.Owner != null)
{
this.Owner.Activate();
}
}
}
(Note that the workaround will always bring the main window into foreground which might be different than the expected behavior)