|
Fully understood. Thanks so much for your time - it's really helped! Uses for dependency properties seem to be a lot more obvious now too... Cheers!
|
|
|
|
|
Is it possible to derive a reusable class from System.Windows.Application? I want to make an "ApplicationEx" class with some extended functionality.
Problem is that App is derived from System.Windows.Application and its a partial class, so if I change App to derive from a class that derives from Application instead of deriving from Application directly, it doesn't jive with the App.g.cs code behind.
What I mean is:
public class ApplicationEx : ApplicationEx
{
}
public partial class App : ApplicationEx // instead of Application
{
}
I don't want to loose app.xaml functionality.
|
|
|
|
|
Never tried that, so not sure if another error will pop up, but you can get around that particular error easily.
The App.g.cs file is generated by the XAML compiler. If you check out the App.xaml file, you'll see it starts with:
<Application x:Class="..."
That "Application" tag is the one that has to change to ApplicationEx (With the appropriate namespace prefix), in order to make the App.g.cs match.
|
|
|
|
|
Lol, yeah, I'm a total idiot. I forgot about that part of the change. I was just about to delete the post when you posted .
|
|
|
|
|
|
Hmm... it didn't really work after all.
ApplicationEx lives in a seperate assembly. ApplicationEx has (or attempted to have the entry point in it):
public class ApplicationEx : Application
{
[STAThread]
public static void Main(string[] args)
{
}
}
So after fixing the mistake in app.xaml, it gets past that error, but it doesn't see the entry point in ApplicationEx.
I thought that would work
|
|
|
|
|
So make your own Main function that just creates an ApplicationEx and runs it. You can specify the entry point in a WPF app.
|
|
|
|
|
Yeah, I was trying to encapsulate "everything", but I guess there is no way around having a static Main() in the exe itself.
|
|
|
|
|
Heh, well encapsulating Main() might be a little overboard... I mean, you can always have your ApplicationEx do its initialization in the constructor, or even do a factory-style constructor instead to preserve command-line args (If you need them)...
Application app = ApplicationEx.Create(string[] args);
|
|
|
|
|
Yeah, I ended up having an ApplicationEx.StartupEx method (lol, you can totally tell I come from the MFC / Win32 world with all the "Ex" names) that takes the type for the user application class along with the args and then it creates the application and/or manages the single instance stuff. It does require the user to stub out a Main() and forward the call to my DLL though. I was trying to avoid that. Oh well.
Now I'm just having a bit of trouble figuring out a common place to process the command line for the first and subsequent instances since some of the WPF start up code is syncronous (Application.Run()). I've got it working for the second instance though. It does forward the args to the first instance.
I'm using the WindowsFormsApplicationBase technique to do the singleton app stuff. It does have the different entry points for the first / subsequent start ups (OnStartup / OnStartupNextInstance).
2nd+ instance is going through OnStartupNextInstance and calling a virtual method in ApplicationEx, but 1st instance is a bit trickier since I haven't quite convinced myself if that case should be passed in before the main window is created, but I'm thinking it probably should.
Its weird though... popping up a message box before the main window is created somehow creates the main window...
|
|
|
|
|
Heh, you're losing me here... Not sure exactly what you're trying to do, and I'd never even heard of WindowsFormsApplicationBase until now... Are you starting up multiple GUI threads? Usually don't want to do that in a WPF app, unless you have a really good reason for it.
But anyway...
Yeah, Application.Run() is synchronous. I generally handle command line apps by making a "Globals" static class to hold that and a few other properties... The kind of things that get set once on startup and then never ever ever ever EVER modified... Stuff like command line arguments, modes to turn off non-developer features or prevent external writes during testing... Just don't use something like that for read/write storage, or you'll just create all sorts of design issues.
|
|
|
|
|
I'm making an "ApplicationEx" class that encapsulates single application instance functionality and the WindowsFormsApplicationBase technique is one of the more popular ways to do that. No multi-threaded GUI threads . WindowsFormsApplicationBase is just MSFT's wrapper for that stuff and they do all the inter-process communication like forwarding the new cmd line args to the previous instance.
Think about IE... if you type "start http://www.microsoft.com" at the cmd prompt, it starts up IE and goes to www.microsoft.com. Now if you type "start http://www.cnn.com", it keeps the same one instance of IE, but opens up a 2nd tab to www.cnn.com. Obviously a 2nd instance of IE ran and exited and somehow forwarded the args to the first process.
WindowsFormsApplicationBase provides a pretty clean mechanism to get the SECOND instance cmd line args to the singleton instance, but it doesn't provide a very clean way to get the original instance cmd line args out of the static classes.
I think I'm kind of going to do what you suggested and add a "LastCmdLineArgs" property to ApplicationEx. Kind of weird that Application doesn't have that already.
|
|
|
|
|
Ah, gotcha... I do that with a lightweight launcher EXE that sends args over a named pipe.
|
|
|
|
|
Why not just create this functionality as an extension method and use that?
|
|
|
|
|
Can't do that since ApplicationEx has some added virtual methods (i.e. ProcessCommandLine(...), etc.). You are right though, it would have been cleaner if I was just forwarding a single call. I could have had the user pass in a callback function instead of using virtual methods, but at that point, having an extension method vs. the ApplicationEx class... seems like the virtual method way is a bit cleaner.
|
|
|
|
|
Could you send me what you're trying to do and I'll see if I can get it to work? I've had some experience hacking around in the App class.
|
|
|
|
|
Hey All,
I'm just looking a spot of MVVM and I've written a little demo app with this interface in:
public interface IView<T> where T : ViewModelBase
{
T Model { set; }
}
So in my windows I can do this:
public partial class MainWindow : IView<MainWindowViewModel>
{
public MainWindow()
{
InitializeComponent();
}
public MainWindowViewModel Model
{
set
{
DataContext = value;
}
}
}
And it will automatically type my Model property for me ... amazingly lazy but I kinda like it. I'm just not sure how 'MVVM' it is ...
What are your objections? This isn't an interface for every ViewModel type but works well for Window / Region / Views (proper) type view models ...
Cheers,
|
|
|
|
|
It's probably not that useful: it's rare that you want to manipulate a view's view model – what a mouthful that is – in a generic way, through ViewModelBase. But I think it's quite elegant, and it clearly shows (and enforces!) the M-VM relationship.
|
|
|
|
|
Yeah, it really is a 'swings and roundabouts' kinda issue isn't it ...
Strictly speaking the view still doesn't now anything about the model. The only thing it does know in this scenario is the type it will accept as the view model.
99% of the time your unlikely to want to be switching the type of view model you inject into the view data context.
The only thing I don't like is you now only deal with concrete types for view models rather than an interface.
|
|
|
|
|
To be honest mate, if I were you I would use MefedMVVM instead. It gives you the type to interface, and takes care of hooking up the concrete implementation for you.
|
|
|
|
|
Hey Pete,
Will look into this. Looks good!
Cheers,
|
|
|
|
|
It is - I did a minor part of the development for Marlon. It's top notch stuff.
|
|
|
|
|
Nice!
|
|
|
|
|
<slaps forehead=""> ...
I'm still on .NET 3.5 SP1 at work ...
|
|
|
|
|
Personally, I'm more a fan of including a controller in there. I kind of mix MVVM and MVC together.
My class defenitions then look like this:
public class SomeController : Controller<ISomeView, SomeModel>
public class SomeModel : Model
public class SomeView : View<SomeController>, ISomeView
In the constructor of the view, I'll create the controller, which exposes a model property.
That model will then be set on the datacontext. When creating the controller, I'll pass the view to the constructor so that the controller has a reference to the view as well (under the form of an interface).
This way, you can unit test the controller and assert your model states while mocking the view... and, you won't have any ugly code-behind in your *.xaml.cs file, aside from some eventhandler methods like a button_Click. And in those methods, you'll only have 1 line anyway, which will be a controller call like Controller.XButtonClicked() or whatever.
For LOB applications, this works great.
This also opens up a lot of possibilities for standard control behaviour you may wish to have like automatic busy indicators etc.
modified on Thursday, April 28, 2011 8:10 AM
|
|
|
|