WPF: How should I organize my code amongst the source files? - wpf

I see a Window1.xaml and its associated .cs file, which are the main window. Then there's also app.xaml and app.xaml.cs. First, what is the point of App? It seems to be empty.
I'm assuming I should put local variables to the Window on its cs file, and variables related to the whole program on App?

You should MVVM. Start early, win often.
App.xaml and its code file are used for application-wide resources and code that needs to run on startup. You shouldn't be putting anything in app.xaml.cs unless you need to.

App.xaml and App.xaml.cs is your applicaton's entry point. Main() is actually auto-generated and hidden in the partial App class. In the XAML, you can set the Window that will initially display, so you are not forced to use Window1.
In reality, you don't need App.xaml either. In some applications I have made, I have instead opted to create an App.cs, where I manually create the Main() entry point and start the initial Window. If you don't need such fine control over your Main() method, I'd recommend keeping the default XAML method of startup. You can still subscribe to events in App's constructor using the XAML method, for startup code and handling unhandled exceptions.
You should put local variables with the class that needs them. Global variables are bad, but it's be better to use static classes and variables instead of inserting the unnecessary code in App.xaml.cs.

Related

Can I prevent App.g.i.cs to be generated?

According to http://stuff.seans.com/2008/07/11/hello-wpf-world-part-1/, it is generated automatically.
Can I prevent to create it so that I can create my own version ?
In App.g.i.cs contains a function Main() is a standard entry point for an application and it is created automatically. If you want, you can provide your own class that implements Main() Link:
We can write in some other classes like Window1.xaml.cs. Then how the system identifies which Main() should get called. That too simple. Go to project properties, select application tab, then change the start up object to Window1.cs.
Here are the three approaches to add your own implementation of App.xaml:
Approach 1
You can delete the existing App.xaml and App.xaml.cs and add a new class file and maybe call it App.cs. In this you can define the App class and write your own Main method as below.
Approach 2
You will run into issues with Approach 1 if you are adding resources and resource dictionaries to your App.xaml. Since the App.xaml is no longer present you will have to write code in your App.cs itself to manage the resources and the merged dictionaries. However this can be more easily handled by modifying the .csproj file and marking App.xaml as Page instead of ApplicationDefinition.
Approach 3
If you have resources and hence want to have App.xaml, but don't like to tamper with .csproj file, then you can include another class in your project that defines the Main method as below.
Also, you can see this link:
Living Without App.xaml and still being able to use Blend

Does calling a ScriptableMember method on a Silverlight control from JavaScript create a new Instance of the control?

I have a Silverlight control with a method named DoSomething() decorated with the <ScriptableMember()> attribute. I then call this method successfully from JavaScript and proved by a little message box that apprears from the SL side that says "Method Called!".
Point is all that works. The problem I am having is that prior to calling this method I build up an ObservableCollection on the Silverlight control containing 1..n FileInfo objects. This works fine too and builds up as I add files to it. Each time I add a file, a messagebox tells me the count from Silverlight (i.e. "Count = 2").
Now the problem: when I call the method DoSomething() from JS and access that ObservableCollection the count = 0! To see what is going on I placed a message in the Silverlight control's constructor to see if it gets entered upon being called from JS, and indeed it does and appears to recreate the control.
If this is the case it kind of makes sense that my ObservableCollection has a count = 0 because it is not the same control instance where I built up the FileInfo collection.
So how in the world do I preserve the collection, and why would simply calling a method exposed to JS from Silverlight, recreate the control and not allow me to access it's given state? I don't want a new control, I need to manipulate it as-is. Or am I off base and doing something else wrong to cause this beahvior?
Thoughts? Thanks!
It turns out the instance registered was the culprit. The MSDN examples show registering a new instance of the type, but in my case I needed the actual instance of the Page Control itself which solved the problem.
So at the completion of my page's initialization, I could register the current page's instance like below:
HtmlPage.RegisterScriptableObject("SLControl", Me)
This allowed me from JS to access the control in it's current state which included all objects in the ObservableCollection as required. I blogged about this topic with code examples and the article below expands on this situation:
Get A Silverlight Control's Current Instance For Communicating Via The HTML Bridge:
http://allen-conway-dotnet.blogspot.com/2012/03/get-silverlight-controls-current.html

Call a method in app.xaml.cs from ViewModel

I have some common code written in three ViewModels, which should be refactored. I have moved the code in a method in app.xaml.cs. Is this a right approach ? Now I have to call this method from the ViewModels, should I raise a custom event (from all ViewModels) and handle it on the app.xaml.cs ? If yes that would mean I have to create references of the ViewModels on the app.xaml.cs page (we are using Unity).
Does this seem right ? I am new to MVVM, any other suggestions ?
Any help will be appreciated.
You haven't mentioned what the code is. Why is it in the App.xaml.cs file?
The fact that you need to call it from three different ViewModels would indicate that you should refactor it into either:
a static helper type class
a base class that your ViewModelss inherit from
The ViewModel's job is to hold and shape (or transform) data ready for display, but it shouldn't know about the display. Nor should it know about the contents of the App.xaml.cs, especially as your ViewModels may end up being in a totally different module or assembly to the App.xaml file.
Any time you have "Cross cutting" challenges like where 2 totally separate objects need to communicate, an event style (publisher/subscriber) pattern works well.
If you are using Unity, then use the EventAggregator.
That way you can simply publish an event from your VM and have your app.xaml.cs listen for the event.
this way you wont have to let your VM know about app.xaml.cs.

WPF app startup problems

My brain is all over the map trying to fully understand Unity right now. So I decided to just dive in and start adding it in a branch to see where it takes me. Surprisingly enough (or maybe not), I am stuck just getting my darn Application to load properly.
It seems like the right way to do this is to override OnStartup in App.cs. I've removed my StartupUri from App.xaml so it doesn't create my GUI XAML. My App.cs now looks something like this:
public partial class App : Application
{
private IUnityContainer container { get; set; }
protected override void OnStartup(StartupEventArgs e)
{
container = new UnityContainer();
GUI gui = new GUI();
gui.Show();
}
protected override void OnExit(ExitEventArgs e)
{
container.Dispose();
base.OnExit(e);
}
}
The problem is that nothing happens when I start the app! I put a breakpoint at the container assignment, and it never gets hit.
What am I missing? App.xaml is currently set to ApplicationDefinition, but I'd expect this to work because some sample Unity + WPF code I'm looking at (from Codeplex) does the exact same thing, except that it works!
I've also started the app by single-stepping, and it eventually hits the first line in App.xaml. When I step into this line, that's when the app just starts "running", but I don't see anything (and my breakpoint isn't hit). If I do the exact same thing in the sample application, stepping into App.xaml puts me right into OnStartup, which is what I'd expect to happen. Argh!
I've also just created a new WPF application from scratch, removed StartupUri, overrode OnStartup(), and it also works. WTH?
Is it a Bad Thing to just put the Unity construction in my GUI's Window_Loaded event handler? Does it really need to be at the App level?
Double check that the x:Class in App.xaml in the same namespace/class as in your App.xaml.cs. It's easy to copy/paste from another project and to forget to modify this.
If for any reason you don't manage to solve this, remove the App.xaml and add a Main() which does a new App().Run(). If this doesn't work either, there's something really odd here.
Your problem doesn't seem related to Unity at all... Make sure that :
the startup object is set to YourProject.App (in the project properties page)
the build action for App.xaml is set to "ApplicationDefinition"
Otherwise, I can't see any reason why it shouldn't work...
Update : just another idea... Try to set the StartupUri back to App.xaml, and call the base implementation in OnStartup :
protected override void OnStartup(StartupEventArgs e)
{
container = new UnityContainer();
base.OnStartup(e);
}
In my case, I hit the "something really odd" part that Julien Lebosquain referred to.
I kept checking and re-checking names, namespaces, event handlers etc and couldn't see anything wrong but still my WPF MainWindow.xaml kept opening first, bypassing the required startup method.
Eventually, I deleted MainWindow.xaml ... but STILL it popped up first. At which point, I cleaned the solution, deleted the binaries from disk (after altering the start-up project) and closed and re-opened the solution.
This 'fixed' my problem.
I had a similar problem -- My App constructor and OnStartup weren't being called (breakpoints not being hit). In case someone else runs across this thread, here's another thing that can go wrong.
I have a solution with several apps, one of which is just a utility I use to manage some XML files. It doesn't get used much, so I basically forgot about it. Originally, my builds were for "Any CPU", but recently I had to change them to "x86" due to a library I was using. Today, I needed to run this utility, but it was crashing and in the debugger nothing in the App class was being called. After checking namespaces (which were OK), I decided to clean the project (as suggested above). When I tried to run the app, I got an error that VS couldn't find the EXE. Apparently, VS was running an old "Any CPU" EXE it found in the output directory which was crashing, and then was deleted when I cleaned the project. I checked the Build | Configuration Manager, and sure enough, I hadn't selected the utility app for the "x86" build. Once I added it, everything worked great. Hope this helps.

WPF - Shut-off autogen of Main in App.g.cs

I'm learning WPF.
I want to provide my own Main method in my App.xaml.cs rather than getting one generated for me in App.g.cs. However I keep getting conflicts because I haven't found out how to stop an additional Main from being generated.
Is there a setting in my project file or elsewhere that controls this?
I found the answer here. http://learnwpf.com/post/2007/12/13/How-can-I-provide-my-own-Main%28%29-method-in-my-WPF-application.aspx
It is:
The way WPF knows to create the Main() method for a particular xaml file is through the build action property set for App.xaml - it has a build action of ApplicationDefinition. By changing this to Page WPF won't create the Main method and you can provide your own in a regular class file you add to the project.
However in the comments to the above blog, a comment notes there may be issues with blend and it references: http://blogs.msdn.com/expression/archive/2008/04/09/creating-a-wpf-blend-project-that-loads-resources-in-code.aspx . I don't fully understand the issues yet.
You can also just create a separate class (for example, Entry) which is responsible for bootstrapping your application. Then go to project settings and set your startup object to Entry. That way you don't even have to disable the autogenerated method.
The easiest way is to set the Build Action in the Properties window from ApplicationDefinition to Page for App.Xaml.
Then you can define your own entry point.
I found a solution:
Copy the data from your app.xaml file
Delete app.xaml file and re-create with the same name
Create `main` method in .cs file, and paste your old copied code into it
One way is to forgo defining an Application-derived class in XAML, so you can manually define the Main method with your custom requirement
The Easy way just create a class like Startup.cs with build action to compile
and remove ApplicationDefinition from App.xaml convert that to page
and remove it from any other file in the application

Resources