I have a WPF window in a project with a XAML file and associated C# code behind file. If I set "StartupUri=MainWindow.xaml" in App.xaml to this window the window opens as expected when I start my application.
However, I want my application to to take command line parameters and then decided if it should open the GUI or not. So instead I've set "Startup=Application_Startup" in my App.xaml file which is defined as shown below.
private void Application_Startup(object sender, StartupEventArgs e)
{
if (e.Args.Length > 1)
{
//do automated tasks
}
else
{
//open ui
MainWindow window = new MainWindow();
this.MainWindow = window;
window.Show();
}
}
Yet when I run this the window displayed is totally blank.
Adding window.InitializeComponent() seems to do the trick:
MainWindow window = new MainWindow();
Application.Current.MainWindow = window;
window.InitializeComponent();
window.Show();
I usually like to have a little explanation on why something does or doesn't work. I have no clue in this case. I can see that the examples online don't include InitializeComponent, and yet I produce the same exact error as you do (event without checking for args).
I created a sample application, and removed the StartupUri and set the Startup to the method you provided. Everything seems to work as expected, the content of the window is displayed, so maybe, as Daniel mentioned, you're missing the call to InitializeComponent method in your MainWindow constructor.
Related
I'm using Visual Studio 2015 and .Net
I’ve come upon a somewhat peculiar problem. I have a C# solution with two projects. One is a standard WPF application, the other a WPF User Control library. The WPF application project is the startup project.
In each project I have one window. In the startup project I open the window and set a value in the logical call context by using CallContext.LogicalSetData. This is done on load. I then close the window and open the window in the WPF User Control library. I populate one textbox with the value in the logical call context (using CallContext.LogicalGetData) and this works fine.
I have a button, which on click fires an event that populates another textbox with the same value from the logical call context – but all of a sudden this value is null.
I can make it work simply by changing the starting window to not do it’s “thing” on load but rather on a button event.
The startup window code:
public partial class MainWindow : Window
{
public MainWindow()
{
this.Loaded += OnLoaded;
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
CallContext.LogicalSetData("test", "value set onload");
TestWindow win = new TestWindow();
win.Show();
this.Close();
}
private void button_Click(object sender, RoutedEventArgs e)
{
CallContext.LogicalSetData("test", "value set on button event");
TestWindow win = new TestWindow();
win.Show();
this.Close();
}
}
As mentioned above, if I comment out the four lines in the OnLoaded method then it works fine.
The other window:
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
PreLoadedText.Text = CallContext.LogicalGetData("test") as string;
}
private void GetValue_Click(object sender, RoutedEventArgs e)
{
string eventTextText = CallContext.LogicalGetData("test") as string;
EventText.Text = eventTextText ?? "The value is null";
}
}
Btw. I tried using the AsyncLocal<T> class - but I just experienced the same problem.
Example solution can be found here:
Visual studio solution as zip file
Note - I'm not looking for a workaround (I have a couple), I'm looking for a reason why this happens.
It's because the instance of Thread.CurrentThread.ExecutionContext, which contains the DataStore of the CallContext, changes between the calls. You can check that if you give it a marker by using "Make Object ID" in the Visual Studio debugger.
Why does this happen? I have absolutely no idea. I tried to debug the .net Framework source without any luck.
As far as AsyncLocal<T> is concerned: It also uses the same Thread.CurrentThread.ExecutionContext and thus suffers from the same problem.
It doesn't happen if you use ThreadLocal<T> because that's using [ThreadStatic] and the Thread itself doesn't change.
This is my App constructor for my WPF application:
public partial class App
{
public App()
{
Run(new Login(false));
}
}
And this is my Login constructor:
public Login(bool ignoreSettings)
{
InitializeComponent();
if (ignoreSettings)
{
TxtUsername.Text = SettingsSaver.LoadUsername();
TxtCrmUrl.Text = SettingsSaver.LoadCrmUrl();
return;
}
if (string.IsNullOrWhiteSpace(SettingsSaver.LoadUsername()) || string.IsNullOrWhiteSpace(SettingsSaver.LoadCrmUrl())) return;
try
{
CrmConnector.ConnectToCrm();
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
catch (SecurityAccessDeniedException)
{
MessageBox.Show(#"Uw inloggegevens zijn niet correct. Gelieve deze te controleren en opnieuw te proberen.");
}
finally
{
Close();
}
}
It starts the App constructor and goes through the Login constructor just fine, but once it reaches the App Constructor again after finishing the Login constructor, it crashes with an InvalidOperationException, with additional information: "Cannot set visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after the window has been closed.
The goal of the constructor is as follows: When the application is first started, I want to check if there are existing settings for this application. If they exist, I want to use those settings to connect to a 3rd party (Dynamics CRM 2011), open the main application window, and then close the Login screen. if they are not there, I want the user to set the settings.
HOWEVER, I also want to be able to start this window from a button on my main screen, in which case it should ignore the default settings and launch the login window again, allowing me to set the settings again.
I already managed to get it to work using 2 constructors, but Resharper complains when i does that because I basically ignore the parameter in the second constructor (the one which I launch from the button on the main screen. I'm trying to have 1 unified constructor so Resharper does not complain. Is that possible?
Edit: I don't want to keep my login window because I create a new window when I change the settings, using the following code in my MainWindow:
private void BtnSettings_Click(object sender, RoutedEventArgs e)
{
Login login = new Login(true);
login.Show();
Close();
}
edit: some clarification:
I don't want to show multiple windows. What I want is:
on startup, launch Login.xaml;
when Login.xaml is launched, check if the settings have already been set;
if no settings, show Login.Xaml for setting;
if Settings set, start MainWindow with saved settings.
In addition, I have a button on MainWindow which has to force-start Login.xaml but not check if there are settings. These are currently separate constructors and I would like to make 1 constructor of them.
Your update makes it a bit clearer what it is you want to achieve. I suggest restructuring the Login window to make it more single responsibility and pushing the validation logic up into the App class so that it is responsible for managing initialization flow. A recipe is as follows:
Alter App.Xaml.cs so that it looks something like this; importantly there is no StartupUri:
<Application
x:Class="MyNamespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources />
</Application>
Where MyNamespace is the namespace of your App class.
Now you are going to manually start the application from App.OnStartup
public partial class App
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
if (!AreSettingsSet())
{
this.MainWindow = new Login();
this.MainWindow.ShowDialog(); // Waits until closed.
// Recheck the settings now that the login screen has been closed.
if (!AreSettingsSet())
{
// Tell the user there is a problem and quit.
this.Shutdown();
}
}
this.MainWindow = new MainWindow();
this.MainWindow.Show();
}
private bool AreSettingsSet()
{
// Whatever you need to do to decide if the settings are set.
}
}
To summarise: remove your validation logic from the Login window to App, only show Login if needed and only show MainWindow if the settings are actually valid.
You will need to do some tweaking and then you can show several windows or single window multiple times.
Remove StartupUri from App.xaml.
Set Build action to Page for App.xaml.
This will disable autogenerating of App.g.ics and you can create own application entry point:
public partial class App : Application
{
[STAThread]
public static void Main()
{
App app = new App();
app.InitializeComponent();
app.ShowWindow1();
app.ShowWindow1(); // show second time same window (new instance)
}
public void ShowWindow1()
{
// show window1 in separate method, so that instance will be deleted after method ends
Window1 window1 = new Window1();
// optional (as it seems)
// MainWindow = window1
widow1.Show();
}
}
Try Visibility.Hidden instead of Close if you want to keep it
Update:
this.Visibility=Visibility.Hidden;
I faced a similar challenge,
make sure that any functions that may close the window you are opening are called after the window has loaded.
for the window you are opening set in the xaml file
Loaded="Window_Loaded"
then in the cs file,
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//call your function here
}
This resolved my issue, hope that helps
It says, I can use Startup event for many things, like initialization, creating multiple forms, blablabla.
However, try to create a new WPF application and add this event handler:
private void App_Startup(object sender, StartupEventArgs e)
{
Window window = new Window();
}
And after closing main window your application will hang up in the memory. Pausing executing in VS at that moment will drop ugly crash call stack window with a lot of calls somewhere far away from my source code.
Any thoughts?
P.S.: I need to instantiate all of my windows for self-learning configuration purpose once. Should I use some other place?
Let me give a better example (example above is good to reproduce the problem, seems it's hard to understand what I am actually doing). I remove StartupUri and then:
private void App_Startup(object sender, StartupEventArgs e)
{
// un-comment this line to reproduce the problem:
// Window window = new Window();
// actual implementation will be
// Window1 window1 = new Window1();
// Window2 window2 = new Window2();
// Window3 window3 = new Window3();
// Window4 window4 = new Window4();
// ...
// start main window as usually
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
And why do I need instances of windows (window1, ..2, ..3, ...)? Because their content will be inspected to create a list of controls for which I want to save configuration. Some of these windows will never be shown to the user (to example, if he is not admin), some of them are popups, some are editors, etc. So I do not want to display them. But at any application startup the configuration has to be created and saved. And I am looking now for the place to do so.
Surprisingly, using dedicated event Startup seems have some problems with creating multiple windows but not displaying them. Question is why and how to solve it.
Testing a bit more. Try this code and explain me, why application is closed without showing any window?
private void App_Startup(object sender, StartupEventArgs e)
{
Window window = new Window();
window.Close(); // closing without opening window
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
//mainWindow = new MainWindow(); // can be un-commented, for absolutely no effect
mainWindow.Show();
mainWindow.Show();
mainWindow.Show();
mainWindow.Show(); // you will not see mainWindow at all, all Show doing nothing
}
More questions. What do I do?
Something what works, but smells:
private void App_Startup(object sender, StartupEventArgs e)
{
Window window = new Window();
MainWindow mainWindow = new MainWindow();
mainWindow.ShowDialog();
Shutdown();
}
Notice, calling ShowDialog (which will make event handler waiting for that window closing) and calling Shutdown right after.
It is still not clear what is the problem in the Startup event handler to create instances of some windows. Any ideas?
By doing this, the window you just created has become the main window: the one specified in StartupUri will only be created right after the start up event. By default, the main window must be closed for the application to shutdown. Since it's never shown, the user has no opportunity to do this and the application seems to hang forever. What you're seeing when the execution is paused is a normal message loop, there is no crash here. Add window.Show() to see your real 'main' window.
Remove the StartupUri attribute from your App.xaml if you decide to instantiate the main window manually. Alternatively, keep the attribute and instantiate the additional windows after the Loaded event from the main window has been fired.
I have solution, which seems pretty good to me. Idea is similar to winforms - do everything in the Main.
This, however, is a bit tricky in wpf (I used this question as a guide):
Remove StartupUri from App.xaml;
Set App.xaml property Build Action to Page (this sounds strange, but it works for desktop application). This will remove Main method from auto-generated classes (App.g.cs and App.g.i.cs).
Add Main method manually into Application:
.
public partial class App : Application
{
[STAThread]
public static void Main()
{
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
// ...
MainWindow start = new MainWindow();
start.ShowDialog();
SomeOtherWindow next = new MainWindow();
next.ShowDialog();
}
}
Now I can directly control which window to show and when (program flow control), as well as there is no more bug with not-closing application when creating instances of windows without displaying them.
The suspicious things are this Page setting and that fact, what I do not instantiate Application, nor I call Run(). I do not know yet, if it will be a problem in the future. Would be nice to know it for sure.
It might be necessary to init application still (to load resources?), then
[STAThread]
public static void Main()
{
App app = new App();
app.InitializeComponents();
// ... the rest
// possibly app.MainWindow = start; or app.MainWindow = next;
// if only 1 window, then app.Run(new MainWindow());
}
I am using Visual Studio 2012 C#. I have created a WPF application project with a main window and added a login window to my project. I want to change the startup window to be my login window but can't seem to do so.
I went to the properties but all I see there is Myproject.app - should it not display the forms of my project?
Anyway I have tried running the window from code as well like so :
Application.Run(new Login());
But that does not seem to work. It gives an error saying :
Error 1 An object reference is required for the non-static field, method, or property 'System.Windows.Application.Run(System.Windows.Window)'
To change startup window update App.xaml by changing Application.StartupUri:
<Application ... StartupUri="MainWindow.xaml">
To change the startup window programmatically go to App.xaml
remove the line StartupUri="MainWindow.xaml" (This will remove the default startup window configuration), now add the startup event Startup="Application_Startup", in App.xaml.cs
private void Application_Startup(object sender, StartupEventArgs e)
{
If(somecase)
{
MainWindow mainWindow = new MainWindow ();
mainWindow.Show();
}
else
{
OtherWindow otherWindow= new OtherWindow();
otherWindow.Show();
}
}
use Application.Current.Run Instead of Application.Run
I'm trying to run a window, close it, and then run a second window, in a similar way that seems to work with Windows Forms.
namespace WpfApplication1
{
public partial class App : Application
{
[STAThread]
public static void Main()
{
Application app = new Application();
//windowMain.Show();
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
MainWindow windowMain = new MainWindow();
app.Run(windowMain);
Window1 window1 = new Window1();
window1.Show();
app.Run(window1);
}
}
}
I've set the Build Action in the App.xaml properties from ApplicationDefinition to Page, but the programme throws an exception when window1 is initialised. What am I doing wrong?
Edit: I've modified the xaml in App.xaml as suggested by first answer and edited main as suggested by the comment.
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
</Application.Resources>
</Application>
but I'm still getting the exception.
OK this is what I've divined so far. The Solution Builder looks for a Main() function. Why its not a WinMain() function I'm still not a hundred per cent clear on. If there is no Main(), you get an error. You can have more than one Main() as long as the Project properties: "Application" page/tab: property: "StartUp Object" is set to point to one of the main()s. This is done from an automatically created drop down list.
When a “WPF Application” project is created, Visual Studio(VS) create an xaml file called “App.xaml”. This is a class declaration where “App” is derived from the “Application” Class. VS also automatically generates hidden files for an xaml file. It creates a “name.g.i.cs” file, when the xaml file is created. It creates a “name.g.cs” file the first time the project is built after the creation of the xaml file. In this case it creates “App.g.cs” and “App.g.i.cs”. These files are hidden by default. To view them, press the “Show all files” button at the top of the Solution Explorer, they can be found in “\ obj\86\Debug” folder. When you delete an xaml file the “name.g.i.cs” and the “name.g.cs” files remain and are not deleted.
The “App.xaml” file’s “build Action” property is set to “Application Definition” when created by VS. When this property is set to “Application Definition” a Main() function is automatically created in “name.g.i.cs”:
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main()
{
WpfApplication8.App app = new WpfApplication8.App();
app.InitializeComponent();
app.Run();
}
When this property is set to “Page”, the Main() function is automatically removed by VS. You can create new “Application” derived classes in code or in xaml. I haven’t found a neat way to do it in xaml. There doesn’t seem to be a template for an xaml “Application” derived class. I created a “.cs” code file and then renamed it to an .xaml file. For some reason VS won’t allow you to have more than one xaml “Application” declaration file set to “Application Build”, it doesn’t even give you the option of choosing one in the "Project: Properties: Application": “Startup Object” property.
As you can see in the hidden Main(), an instance of “App” is instantiated and run. If using your own Main() function: an instance of, the base “Application” class, or an “Application” derived class (whether declared in code or in xaml), can be declared and run. The “Application” class should only be instantiated once and should only be run once. If the “Application” derived class is declared in xaml then a simple application can be run by using the StartUpUri property in the xaml file: StartupUri="Windowname.xaml". Alternatively the top level UI programme logic can be placed in a Startup event handler. If “Startup="Application_Startup" is placed in the “App.xaml” file then an event handler can be written:
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow windowMain = new MainWindow();
windowMain.ShowDialog();
Window1 window1 = new Window1();
window1.ShowDialog();
Shutdown();
}
You have to use ShowDialog() here, because it blocks until the window is closed. If you used Show() instead, it would show one window, then immediately show the other one and shutdown the application. In this case there's no need to call the Run() method yourself, that's done automatically.
The “Application” class instance can be run in code whether its declared in code or in xaml. You can then perform initialisation code prior to calling Run(). This would be placed in the Application_ Startup() event handler using the other way. However, if the “Application.Run” call is ever made in the programme, then no windows should be opened (using show() or ShowDialog()) in Main() or anywhere outside of the Application Class or within events and functions called from those events, called during “Application.Run()”.
The Application class has a ShutdownMode property (Application.ShutdownMode). The default for this is: “OnMainWindowClose”. This property can also be set to “OnLastWindowClose” or “OnExplicitShutdown” in code or in the xaml. You will need to reset this if you don't want the programme to close down when the MainWindow is closed.
I think for my purposes it is better not to use the Application class at all and just call the windows using Show() and “ShowDialog()”. This way I can use WPF pages but I could also call Windows Forms, or DirectX screens, as long as they are not open at the same time, or have no UI at all, if the programme is running remotely. Is there any reason for not doing it this way?
I think your application is shuting down when you close the first window. You need to set Application.ShutdownMode to OnExplicitShutdown.
If all you want to do is to show one window, when that closes, show another and when that closes, shutdown the whole application, you should keep the Build action as ApplicationDefinition, set ShutdownMode to OnExplicitShutdown (probably in App.xaml, but you can it in code-behind too) and put the following code in an event handler of the Startup event of your application:
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow windowMain = new MainWindow();
windowMain.ShowDialog();
Window1 window1 = new Window1();
window1.ShowDialog();
Shutdown();
}
You have to use ShowDialog() here, because it blocks until the window is closed. If you used Show() instead, it would show one window, then immediatelly show the other one and shutdown the application.
There's no need to run the Run() method yourself, that's done automatically.