I am really new to WPF and c#, and have some questions about how the applications are initialized. I am going through some tutorials on LINQ classes in the hopes that I can bind all of my SQL Server data with observableCollections.
One of the examples I found has a start like so (in the App.xaml.cs file):
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow app = new MainWindow();
ProductViewModel context = new ProductViewModel();
app.DataContext = context;
app.Show();
}
}
When I run the application I get 2 main windows. The commands above execute and open the first one, but then a second one gets called from some system code which I can't see (I can see in dissasembler, but that does not really help). So it seems that the application that VS set up for me has a standard entry, but the sample code (from Rachel Lim) does not do this. I have searched for differences in various files (like App.g.i.cs which has the void Main() call) and both my application and the sample are the same. I am trying to "take control" of the application to handle creating my observablecollections with the LINQ classes. Is anyone familiar enough with VS and C# to give me some hints on what might be happening?
The problem is probably in your App.xaml which often has the following:
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">
<Application.Resources>
</Application.Resources>
</Application>
If your App.xaml.cs opens a window in one of the events as you have demonstrated, then you need to make sure to remove that StartupUri="MainWindow.xaml" in your Application element.
Related
I am trying to learn WPF. I have done mostly back-end programming, except I did some C++ UI programming in the nineties. So far, I have created a simple maintenance application with a few screens and I can run it fine. I can navigate around, insert records and whatnot. However, I have to set my app.xaml startup location to MainWindow.xaml and then instantiate my actual window inside the C# code of the class linked to it. If I delete the MainWindow.xaml file and set my StartupLocation to wndMyMainWindow.cs, I get an error saying that it can not find the file. Is there any way around this? It seems sort of weird to require a non C# file type in what is supposed to be a C# UI framework.
In your App.xaml remove the StartupUri="MainWindow.xaml". Then add Startup="App_OnStartup" and create the matching method in your App.xaml.cs file like:
public partial class App : Application
{
private void App_OnStartup(object sender, StartupEventArgs e)
{
// do some code stuff like initializing your ViewModel or something else
// Instanciate the view you want to display and show it
MainWindow mainWindow = new MainWindow();
mainWindow.ShowDialog();
}
}
I have a WPF application without an application.xaml, since I need to do the Main() method by myself. Therefore I neither have an ApplicationDefinition nor an application resource. I currently attach the resource dictionary to the application at the application startup
Of course the WPF Designer complains now about missing resources.
So I want to get rid of two problems:
- I don't want to attach the resource dictionary manually at startup
- I want to get the resources also work at design time in the WPF designer
Is there any help for this problem?
Thanks
Martin
There is a possibility to use the Main() method for yourself
Just delete the following property from the xamlcode of Application.xaml:
StartupUri="MainWindow.xaml"
Then add the following in the code-behind of the Application.xaml:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// My code goes here, but nothing ever happens.
base.OnStartup(e);
}
}
Now you can still use the Application.xaml for your resources and also have your specific startup procedure.
My WPF application calls upon a separate project to handle a login process BEFORE the Main Window in my application is shown. This creates a problem and causes "Application Shutdown" errors because the FIRST window in the application has closed. How can I handle the login process BEFORE my Main Window is shown? Every search I find comes up with references to Prism or MEF... which I cannot use.
If you want to control everything from the very start of your application, you need to create your own main method and use this as "start object" (see project properties). More details can be found in another SO answer, but this is its essence:
[STAThread]
public static void Main(string[] args)
{
// Do anything you like before running the main window.
// ...
// Proceed with usual application flow.
var app = new MyApplication();
var win = new MyWindow();
app.Run(win);
}
To prevent the application shutdown error, you can change Application.ShutdownMode to OnExplicitShutdown. And explicitly call Application.Shutdown Method to close your application when needed.
Have you tried adding code to the App.xaml.cs file? There are places you can place code in there that runs before the main window is opened. In addition to a constructor, there's the Startup event that you can assign a handler to in the App.xaml file:
<Application x:Class="CarSystem.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DispatcherUnhandledException="App_DispatcherUnhandledException"
Exit="Application_Exit"
Startup="Application_Startup"
StartupUri="MainWindow.xaml">
And, of course there's the Main method in the same file that you could throw code into, as well.
I have a Windows Tray project that opens a WPF window when Settings is clicked. The WPF window opens and displays some of the content properly, but I have two lists that are bound to another class that have odd behavior.
These lists are displayed on two different tabs as devices. On one tab, there is a graphical representation from which the device can be started, and the other tab shows the settings for the device. Everything works perfectly when the WPF application is set as the startup project. However, when I start it from the tray, the lists load correctly, and display in the first tab, where they can be started, but the second tab shows no devices present. They are both linked to the same data.
At first, I thought that there was an issue with binding, but after several days of trying to resolve this, I believe the problem is with App.xaml, where there is a reference to a resource. I suspect that since i am not referencing App.xaml, the resource is not loaded, and the list is not being set up properly. The only difference between the project working and not working is that one has the WPF as startup project, and the other uses the tray to call the WPF.
My question, then, is how do I reference App.xaml to ensure that I load the required resource.
Below is some of my code, in case it might help.
App.xaml
<Application x:Class="Sender_Receiver.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Shell.xaml">
<Application.Resources>
<ResourceDictionary Source="Themes\Generic.xaml"/>
</Application.Resources>
Current call to open the WPF
private void settingsEvent_Click(object sender, EventArgs e)
{
gui = new Sender_Receiver.mainWindow(); // mainWindow() located in Shell.xaml
gui.Show();
}
Code to display the devices. A collapsibleSection implements Expander and RepeatControl implements ItemsControl.
<c:CollapsibleSection Header="Senders">
<c:CollapsibleSection.CollapsedContent>
<c:RepeatControl Margin="30,0,0,0" ItemsSource="{Binding SendersList}"
ItemType="{x:Type m:Sender}" List="{Binding SendersList}"
ItemTemplate="{StaticResource SenderSummary}"/>
</c:CollapsibleSection.CollapsedContent>
<Border BorderThickness="1" BorderBrush="Chocolate" Margin="30,0,0,0">
<c:RepeatControl ItemsSource="{Binding SendersList}"
ItemType="{x:Type m:Sender}"
List="{Binding SendersList}"
ItemTemplate="{StaticResource SenderTemplate}"/>
</Border>
</c:CollapsibleSection>
The image below shows how the application is behaving under different conditions.
Any assistance would be greatly appreciated.
I finally figured this one out. Instead of instantiating the UI, the entire WPF application must be called to run. This will cause the App.xaml to load the dictionary, and other WPF forms can then access it. This is done with the following code:
private void settingsEvent_Click(object sender, EventArgs e)
{
if (gui == null)
{
gui = new App();
gui.MainWindow = new mainWindow();
gui.InitializeComponent();
}
else
{
gui.InitializeComponent();
gui.MainWindow.Show();
gui.MainWindow = new mainWindow();
}
}
private static App app = new App();
You must keep adding the mainWindow back to the App, as it seems to be set to null when the window shows.
This was discovered through experimentation, so i am sure it is not the best practice, but it works, and right now, that was what I needed.
EDIT
For my purposes, however, this still was not working. I could either open the Settings window only once, or I could not get an event handler to work on it the first time it was open. Finally, Josh came up with the correct answer:
Process myProcess = new Process();
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = "C:\\mysettingsapp\\mysettingsapp.exe"; // replace with path to your settings app
myProcess.StartInfo.CreateNoWindow = false;
myProcess.Start();
// the process is started, now wait for it to finish
myProcess.WaitForExit(); // use WaitForExit(int) to establish a timeout
His full explanation can be found here.
I am trying to use a .NET 4 SplashScreen in a Prism based WPF application. I have used the SpashScreen by setting the build action on the image to SplashScreen.
The application used to keep on crashing with a System.Resources.MissingManifestResourceException. Finally I figured out that if I add a StartupUri="MainWindow.xaml" in the App.Xaml file, the SplashScreen works fine.
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
</Application>
But in a prism application, we cannot have a StartupUri. Everything is done in the Bootstrapper.
So what do I need to do manually that StartupUri did to make the SplashScreen work?
Update 1: The complete exception message is:
System.Resources.MissingManifestResourceException was unhandled
Message=Could not find any resources appropriate for the specified culture or the neutral culture. Make sure
"Application.g.resources" was correctly embedded or linked into
assembly "Application" at compile time, or that all the satellite
assemblies required are loadable and fully signed.
Update 2:
I have figured out the adding or removing the StartupUri does not matter. What matters is that I have an additional WPF Window (other than App.xaml) or 2 dummy entries in the App.Resources tag.
<Application.Resources>
<Style x:Key="Dummy"/>
<Style x:Key="Dummy1"/>
</Application.Resources>
If I do not do this, the Application.g.resources file is not created in obj file and hence not embedded in the executable.
Adding two dummy resource entries was brought to my attention by this blog post.
Update 3:
My question was answered by Bob Bao on MSDN forum here. Also It seems Kent was trying to point me in the same direction.
Do not set the build action of the image to SplashScreen. Instead:
Add the code in the App OnStartup method as:
protected override void OnStartup(StartupEventArgs e)
{
SplashScreen splashScreen = new SplashScreen("splashscreen.png");
splashScreen.Show(true);
base.OnStartup(e);
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
"splashscreen.png" is one image in the project, and its "Build Action"
is "Resource".
Simply define your own entry point which firstly shows the splash screen and then bootstraps Prism. In your project properties, set the entry point to your custom entry point.
internal static class Entry
{
public static void Main(string[] args)
{
var splashScreen = ...;
splashScreen.Show();
var bootstrapper = ...;
bootstrapper....;
}
}
Please check this adress : http://prismsplashscreen.codeplex.com/
There is a full example with prism