No more posts from me for the next ten days. My wife and I are going to the Galapagos Islands. No computer. No phone. No twitter. Heaven.
Thursday, May 28, 2009
Can I write a WPF+Silverlight App?
In this post we explore the question, “can it be done ?”
If we were asking “can we write one application that targets both Windows Forms and ASP?”, I would say “sure but there will be little code in common.” The data access and business layer perhaps … if you are careful. At the application, UI, and presentation levels there are irreconcilable differences. Maybe 10% to 20% of the code can be the same in both environments. That’s my opinion based on recent observations of such a case.
I believe the story is much better when it comes to writing a single application with both a Silverlight and a WPF face. It helps enormously that they share the same presentation philosophy, the same UI specification language (XAML), the same client-side execution model, and many of the same components.
According to my calculations for Silverlight v.3, you will be able to re-use between 52.6% and 93.7% of your code-base to support both platforms.
I’m sure you are wondering … why the big spread?
Let’s walk up the application stack and evaluate the opportunities for re-use at each level.
Let us stipulate that we can use the same database regardless of client technology.
You can write a 99% common data access and business layer … at least you can if you adopt my company’s DevForce product; Rocky’s CSLA.NET for Silverlight may be another option.
This high percentage presupposes that you are prepared to use the same asynchronous server-access in your WPF application that you must use in your Silverlight application. Silverlight only permits asynchronous communications with the server. This means you can’t issue a query and block the UI thread until the data arrive. You must design and develop a user experience that keeps going while the program is waiting for data.
Some argue that this is a good idea anyway. Unfortunately, only a handful of developers have experience writing non-blocking UIs. You should anticipate a slower initial pace of development as the team learns to program in async style.
North of 90% of your non-visual application layer classes can be written once and “shared” between regular DotNet and Silverlight assemblies.
The word “shared” deserves at least passing comment. The DotNet and Silverlight assemblies often look alike but they are not the same. Your Silverlight projects must be compiled against Silverlight assemblies; your WPF projects must be compiled against DotNet assemblies. Obviously you don’t want to duplicate your code. The trick is to arrange for the two kinds of project – Silverlight and WPF – to share the same physical code files. You can do this manually in Visual Studio but it is far more convenient to use the Project Linker from Microsoft Patterns and Practices.
Rocky Lhotka presented techniques for coordinating bi-platform development in his Tech Ed 2009 talk “WUX313 Sharing Code between Your Microsoft .NET Framework Applications and Microsoft Silverlight”; I hope a public link to his talk becomes available soon; you can always ask Rocky for it.
You can rely on Prism to glue your application together because Prism was built to support multi-platform scenarios.
XAML is the Problem
It is the visual classes – the XAML files in particular – that present a significant challenge.
There is no issue if you’ll have one look for Silverlight and a different look for WPF. The Model-View-ViewModel pattern makes it easy to share the non-visual Model and ViewModel classes across platform; all you have to do is whip up your separate View XAML files and – shazam! - you’re done.
Did he really say “whip up your separate XAML files …”? He’s got to be kidding!
Yes I am kidding. Unless you’re auto-generating your views (which I cannot recommend), you will invest heavily in crafting XAML that both looks good and enhances user productivity.
If you decide to produce different views for each platform – and there are strong arguments for doing so – you’ve just identified the 50% of your application (measured in effort if not in kilobytes) that will differ across platform.
On the other hand, if you intend to use the same views – the same XAML – on both platforms, you can hope for 90+% XAML re-use, thus bringing your total for the application to the coveted 93.7% mark.
So there’s the spread: 50% common code if you have separate views and 90+% if you have shared views. No brainer, right?
Not so fast. The effort and compromises essential to re-use XAML can be daunting. WPF and Silverlight XAML are similar but maddeningly different in critical details. I won’t explore these differences in depth here but I will call out a few of the obstacles.
First, there are many features in WPF that don’t exist in Silverlight 3. Implicit styling is one example but there are numerous others. Because WPF is (mostly) a superset of Silverlight, if you design for Silverlight you’ll have a better chance of retargeting the XAML for WPF.
Second, there are features of Silverlight 3 that are not yet in WPF-proper such as the DataForm. It will show up eventually but you’ll have to wait for it.
Third, some of the features available on both platforms happen to be declared in different namespaces; Shawn Burke posted about this back in November 2008 and I don’t believe the incompatibilities have been resolved in Silverlight 3. If I recall (to be confirmed) the VisualStateManager is one crucial example of a component that is not in the same namespace on both platforms.
As it happens, you can define a namespace that doesn’t exist in your XAML file as long you don’t reference it. Your app will build and run fine with a phantom namespace declaration such as xmlns:dummy="dummy". You might think this would provide some relief. You could define one prefix to refer to the WPF namespace and and a second prefix to refer to the Silverlight namespace. But which prefix do you use when you want to declare a VisualStateManager? You can’t toggle prefixes.
Fourth, XAML does not support compiler directives (#if/#else/#endif), namespace aliasing, or partial class files. Why does this matter? Because we use all three of these techniques to manage the inevitable differences between WPF and Silverlight implementations … when managing such differences in code.
If XAML supported compiler directives, for example, we could work around the dueling namespace prefix problem with something like this:
<!-- This does not work! -->
#if SILVERLIGHT
xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
#else
xmlns:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"
#endif
You can find a XAML pre-processor that will recognize and resolve compiler-like directives in XAML. Sadly, you won’t be able to use the visual design tools (e.g., Blend) because they won’t recognize or honor the directives.
I hope you will join me in asking Microsoft to make support for conditional XAML a priority.
Netting It Out
It is reasonable to contemplate writing a single application that sports both a WPF and Silverlight client experience.
It isn’t automatic. Microsoft could make it easier … and eventually will. But the important take away is that you can do it and it is relatively easy today if you are willing to write distinct Silverlight and WPF XAML files.
In a future post we’ll talk about who wants to write a WPF+Silverlight application and why.
Wednesday, May 27, 2009
Are We Overselling Prism?
A very good friend just hung up on me in the middle of an IM exchange about whether “we” are over-hyping Prism and recommending it for situations in which it is overkill. He said yes; I said no.
Ok, he didn’t actually hang up on me; our IM connection failed.
I’m replaying our exchange … and because he bailed,however involuntarily, … I get the last word.
-----
Friend: [So-and-so] thinks that [some people] are starting to push Prism in cases where they shouldn't.
Me: Such as?
Friend: They are saying that anyone who builds line-of-business (LOB) applications with Silverlight should use Prism. He doesn't agree. He thinks that most of Prism is good only for Composite UI, with a few exceptions like delegate command, and the project linker. I agree with him. Prism is not the “end-all” for every solution.
Me: True ... but it's the right call for modular solutions. And the bootstrapper + Dependency Injection (DI) are pretty much central to anything I would build.
Friend: Anything YOU build yes. But I don't think you can assume that DI is a given. You can't make using DI a “must”. Sure, for composite apps it makes total sense. For TDD (Test Driven Development) and decoupling of components yes ... but I won't go as far as to say "you must".
Me: It isn't a “must”. Nothing is a “must”. But come on ... once you're comfortable with DI, you never want to be without it again. It is trivial to put in place, easy to use, and it makes writing single-responsibility code every so much easier. And testing, by the way, is NOT why I like DI. You get the major benefits of DI without writing a single test.
Friend: In general I agree but there is a bit of self-selection there. I mean DI appeals to you...and me, and others like us but that does not mean it is something that will work for everyone or that they will perceive the benefits.
Me: No, this is not a case of elitist self-selection. DI does benefit everyone. I think you do the inquiring developer a disservice by supposing that they will be unable to see the value. Look, if you don't want guidance ... if you just want to wing it, then don't ask for my advice. If you want guidance, than I say that something like Prism is good for you in almost any business application.
Friend: Huh? I would be careful if I were you. You’re starting to sound dogmatic.
Me: I'm trying to respond authentically to the developer who asks "how do I build an app?"
Friend: It sounds like you’re recommending a swiss army knife. I would be very wary of that!
Me: No, I don’t thing so. There are some standard problems in any business app ... and Prism ... or parts of it anyway ... and I include it's promotion of certain patterns ... Prism addresses those standard problems. DI is NOT a swiss army knife part. Neither is the bootstrapper. And every app has some kind of shell. These constructs are basic to just about any application.
The other Prism components you may safely ignore until you need them. You may not need Regions and Commanding and Event Aggregator during the first weeks. Not to worry. They are non-intrusive. They are waiting for you, quietly, causing no trouble at all. When you do need them, they’ll be ready for you.
Do you want to argue that the presence of unused components is indicative of a "swiss army knife” syndrome? You might as well say that WPF and Silverlight are swiss army knives because they have loads of features you will never use.
Friend: Not the same.
Me: I'm listening. Why not?
Friend: I don't think you can assume that every app must use modules. I don't think you can even assume the bootstrapper needs to be there. Why would I need a bootstrapper? I have Main.xaml as a shell.
Me: I didn't say every app needs modules. You could use Main.xaml as the shell. But what happens is that all of the other jazz that happens at start-up tends to be piled into Main.xaml or App.xaml. This practice is almost always bad. You’re combining the view that defines the application’s screen real estate with initialization logic; these are wildly different concerns. You really SHOULD think about how the application starts as as a thing unto itself. Failure to do so leads to trouble.
Friend: If I am not writing a Composite UI , why do I care?
Me: You care because the app.xaml gets out of control very quickly as more and more initializations mingle with the code to support how your application hosts it’s views. That is the “shell” function. I’m talking about all of the little services you’ll need – logging, authentication, authorization, persistence, email - you want to register them somewhere. This is bootstrapping, not view hosting; these start-up activities belong in a dedicated class.
And if you're NOT thinking in terms of these services – if you’re thinking you’ll introduce these capabilities by “new-ing” up classes or referencing singletons wherever you need them – you’re heading straight for the kind of hopelessly entangled, brittle application that gets progressively harder to maintain and evolve.
Friend: You realize you do come off a bit biased don't you? I know everything you are saying and am being a bit of devil's advocate.
Me: I realize I am talking to you and so I can make some aggressive claims in my argument without serious risk of contradiction. I don’t think my present approach will persuade the uninitiated. But I resist the notion that I am being “biased”. By charging “bias” you are suggesting that I am somehow an unthinking captive to an ideology. That’s the easy, simplistic way to dismiss advice of any kind.
It is not just a “bias” when I tell you that maxing out your credit card with no ability to pay puts you on the road to trouble.
I see a lot of applications. I see a lot of applications go wrong. They tend to go wrong in the same way over and over again.
The concepts that Prism fosters help you find a way out of those familiar mistakes.
Friend: look I am not saying Prism is bad ...
Me: And I will agree that it is not a magic bullet.
But it is more than a collection of components, more than a bag of tricks. If it were only that, you could argue that the tricks were needed only for applications of sufficient sophistication.
I think Prism is something completely different. I think it is is a lens that helps us see farther and more clearly. Through that lens we can find solutions to the problems that would otherwise mire us in the half-measures that gradually slow our progress and make our code stink.
And, by the way, when I say “Prism”, I mean it to stand in for any such ensemble of guidance and infrastructure code. What Prism-like thing you actually use could come from anywhere; you could write your own. The Prism that comes from Pattern and Practices is just an instance of what I have in mind.
Instant Messenger: Your friend signed off at Wed May 27 01:36:30 2009. This user is offline. Your messages will most likely *not* be received!
Me: Grrrr
------
Feel free to chime in yourself.
Tuesday, May 26, 2009
Event Aggregator in Prism Explorer
I first showed PE (in a slightly different version) at Tech Ed 2009 in a talk I gave on migrating an application to Prism; you can see the video of my talk here.
EventAggregator (EA) is one of the Prism components I discussed; it’s an implementation of the Event Aggregator pattern.
Event Aggregator Pattern
The EA pattern helps us decouple publishers and subscribers. You’ll want it whenever you find yourself in this pickle: your object needs to know when something has happened … but it can not know who will tell it when that thing happens. In other words, the subscriber does not know the publisher of an event it cares about. It doesn’t know if a publisher exists; there might be multiple publishers.
In everyday .NET eventing, the publisher never knows who is going to subscribe. But subscribers at least know the publisher. That’s why we can write a line such as “publisher.SomeEvent += subscriberSomeEventHandler;” No such luck in our scenario.
EA pattern addresses the problem with a little indirection. The pattern refers to an EventAggregator “service” that acts as a broker between publishers and subscribers. Both publishers and subscribers know the EA even if they don’t know about each other. A subscriber registers its interest in a particular event with the EA by handing the EA an appropriate event handler. The EA keeps track of the subscriber and its event. When a publisher wants to raise that event, it publishes to the EA. The EA accepts the published information (a parameter of the published event) and calls all of the subscribing handlers.
There is one significant detail I neglected to mention. The publishers and subscribers must jointly agree on the event itself. They may not know each other but they must have joint knowledge of the same event.
There are plenty of ways to go about this. They could agree on a string name for the event; that’s how it was done in the Composite Application UI Block.
Prism adopts a different approach. In Prism, an event is an instance of a class that derives from CompositePresentationEvent<T> where T is the type of the “event payload”. The “event payload” is the parameter the publisher included when raising the event and that the EA forwards to the subscriber event handlers. The payload type can be any type you like and is typically a custom type.
In Prism, you define the event class and its payload class in an assembly referenced by both publishers and subscribers. Prism applications tend to keep shared information of this nature in an “infrastructure” assembly. Although modules do not reference each other, they do reference this infrastructure assembly.
One last thought. When you follow the CLR eventing convention, the publisher is one of the parameters passed to the event handler. That’s why your handlers look like “void SomeHandler(object sender, EventArgs e);”.
It makes sense that the handler should know who raised the event – who the sender is; after all, the subscriber attached the handler to the publisher. The handler can cast the sender to a known type and, potentially, call back on to the publisher through its public API.
But in our decoupled world, the subscriber shouldn’t know the publisher. In principle, the subscriber would not know how to cast the sender. Accordingly, event handlers used in the EA pattern do not take a sender parameter. They only accept a payload.
And there is a corollary thought; events of this kind should be “Fire and Forget”. The publisher, in raising the event, does not know if anyone is listening and should not expect a response. A subscriber shouldn’t attempt to respond.
No one can stop you from burying the sender (the publisher) in the payload and making it available to the subscriber through an interface defined in the infrastructure assembly. I would strongly discourage such practice. It violates our expectations for the pattern and likely leads to hours of aggravation as some poor sod tries to figure out which subscriber did (or didn’t) make a call back into the publisher (which publisher?). Add multi-threading to compound the confusion. Stay away. If you must report back, consider raising another “completed” event that the publisher can subscribe to. You have been warned!
That’s your informal, breezy description of EA within the Prism world. You can learn more about the pattern by searching for “Event Aggregator”. You can go to Prism for details of the Prism implementation. The balance of this post describes how we use EA in Prism Explorer so that one module can respond to activity in another module.
Event Aggregator in Action
After launch, PE displays two tabs, both populated with an instance of the “Model Explorer View” (MEV). These views were added to the shell by the MEV module. With either MEV instance I can choose a query from a list and see the results displayed in a DataGrid. There are other features here but for present purposes we are interested in the ability to choose a query and see results in a grid.
Here is a snapshot of PE after running an Employee query
This view looks much the same as long as I run a query returning anything other than a Customer query. When I run my first Customer query, a new tab appears, “Customer Orders”
When I click on the new “Customer Orders Tab” I see a master/detail display of the first customer in the grid. Because I selected “All Customers”, the first displayed is “Alfreds …”. The “Customer Orders” view displays “Alfreds …” and its orders.
If I return to either of the “Model Explorer View” tabs, select a different customer, and then return to the “Customer Orders” tab, the newly selected customer is displayed with its orders.
What Happened
At launch, the PE Bootstrapper class loads and initializes two modules, MevModule and CustomerOrdersModule.
The MevModule displays the “Model Explorer View” in the two tabs. When the user picks a query, the query results arrive and the ModelExplorerViewModel publishes an EntityNotificationEvent to report that a new entity has become the “current entity”. As the user moves up and down among the grid rows, the ViewModel publishes an EntityNotificationEvent to the EventAggregator indicating the newly selected “current entity”.
Note that there is no query when the application launches … and therefore no entities to talk about. The ViewModel will only publish when the user selects a query and that query’s execution returns entities.
The ViewModel publishes a notification about whatever entity is newly selected. That could be a customer; it could be an employee, or order, or something else.
Now rewind to application launch. The application Bootstrapper also instantiated the CustomerOrdersModule and initialized it. We don’t know whether it did so before or after creating the MevModule … and we don’t care.
Prism called CustomerOrdersModule.Initialize() which, after some configuration, instantiates a CustomerOrdersCoordinator.
The CustomerOrdersCoordinator starts listening for notifications about Customers by subscribing (via the EA) to the EntityNotificationEvent.
The CustomerOrdersCoordinator treats every EntityNotificationEvent as an opportunity to display a Customer and its Orders. It knows which customer to display by virtue of the EntityNotificationSpecification payload that describes the entity’s type and id.
Of course not every notification will be about customers. The coordinator checks the type of entity mentioned in the event and ignores non-customers.
When the coordinator sees a customer-related event, it checks first to see if it has created a “Customer Orders View”.
If you followed my earlier post on the Coordinator “pattern”, you know that a coordinator’s primary job is to create Model-View-ViewModel (MVVM) triads.
In this application, we didn’t want to show any view … not even the tab to hold a view … unless and until the user queried for customers. At this point in our story, the coordinator hasn’t created a view yet.
Having seen its first customer notification event, it creates the “Customer Orders View” MVVM triad and (using Prism regions) adds the view to the main region of the application shell. It then tells the CustomerOrdersViewModel which customer to display. The ViewModel takes it from there.
Henceforth, whenever the coordinator hears a customer notification, it tells the ViewModel to update itself (and its view) accordingly.
Should the CustomerOrdersViewModel be a subscriber?
That is certainly an option. The coordinator could have turned the listening duties over to the ViewModel, unsubscribed, and disappeared.
I chose a different path for these reasons. If the ViewModel were to subscribe and respond, it would duplicate much of the subscription code that the coordinator is using to bootstrap the MVVM triad. I don’t like to duplicate code and this would have lead me to factor the duplication into some helper class which is just another moving part.
Perhaps as important, I like that the ViewModel doesn’t know how to acquire its model. This frees the ViewModel to concentrate exclusively on supporting its view. These more limited responsibilities make it easier to understand and easier to test.
In sum, I’m happy to keep the coordinator around and let it “coordinate” the ViewModel as well as instantiate it.
Code Fragments
Now that we have the outlines of the story, we can show the fragments of code that are most likely to interest you. The entire code can be obtained from here.
EntityNotificationEvent and EntityNotificationSpecification
namespace PrismExplorer.Infrastructure {
public class EntityNotificationEvent : CompositePresentationEvent<EntityNotificationSpecification> {}
public class EntityNotificationSpecification {
public EntityNotificationSpecification(Type entityType, object entityId) {
EntityType = entityType;
EntityId = entityId;
}
public object EntityId { get; private set; }
public Type EntityType { get; private set; }
public bool IsType<T>() { return IsType(typeof(T)); }
public bool IsType(Type entityType) { return EntityType == entityType; }
}
}
We see that these classes are defined in the application’s infrastructure assembly which is referenced by both the MevModule and the CustomerOrdersModule.
Event Publication
The following two methods appear inside ModelExplorerViewModel, a class of the MevModule:
private void PublishEntitySelected() {
var spec = GetEntityNotificationSpecification();
if (null == spec) return;
PublishEntitySelected(spec);
}
private void PublishEntitySelected(EntityNotificationSpecification spec) {
_eventAggregator.GetEvent<EntityNotificationEvent>().Publish(spec);
}
GetEntityNotificationSpecification is not interesting; suffice it to say that it determines if there is an entity to talk about and, if there is, builds a “specification” of that entity so we’ll know what entity the event is talking about.
The EA (held in the “_eventAggregator” field) was injected into the ViewModel during its construction without developer assistance. It just arrives. Isn’t Dependency Injection marvelous!
We use the EA’s strongly-typed GetEvent() method to retrieve the desired Event object and call that Event object’s publish method, passing along the specification object.
Event Subscription
Here is the CustomerOrdersViewModel subscription method:
protected void Subscribe() {
// Simple subscription - pass in the fn that implements the response
_eventAggregator.GetEvent<CacheClearEvent>().Subscribe(ClearView);
// Full-blown subscription
_eventAggregator.GetEvent<EntityNotificationEvent>().Subscribe(
NotifyView, // the function that implements the response
ThreadOption.UIThread, // invoke subscription on the UI Thread
true, // a true KeepAlive means ensure strong fn references
IsNotificationRelevant // Fn to filter events so only hear pertinent events
);
}
public void ClearView(object dummy) {
if (null == _moduleViewModel) return;
_moduleViewModel.Clear();
}
public void NotifyView(EntityNotificationSpecification spec) {
EnsureViewExists();
_moduleViewModel.RequestCustomer(spec.EntityId as string);
}
Evidently there were some detail I omitted from my story. Time to fill in the gaps.
First, there were two events to consider. The CustomerOrders view needs to know when either the customer has changed or the client cache has been purged.
If you don’t know this application, you don’t know that it maintains a cache of all retrieved entities: all customers, employees, orders, … everything. The application happens to share this cache across the Mev and CustomerOrders modules.
Such sharing is a design choice. It isn’t mandated by anything; it isn’t even a recommendation. It’s just an artifact of this particular design. But it has a consequence. If something clears the cache and the CustomerOrders view happens to be displaying a customer that was in the cache, that customer entity object is no longer “valid for display”. Cache-clearing is a MevModule capability so we must watch out for this.
The ModelExplorerViewModel in MevModule actually raises two events: the EntityNotificationEvent and the CacheClearEvent.
The coordinator subscribes to the CacheClearEvent first. That event is simple. It needs no payload. We can use the lightest Subscribe overload of the Event object which takes a single argument, the handler for the event. ClearView() is the handler in this case; it accepts an object (all handlers must accept some kind of payload, even a dummy) but discards it.
The second subscription reveals the full blown Subscribe() overload. It takes four arguments.
The first is the handler, “NotifyView” in our example. EnsureViewExists will create the MVVM triad and display it in the shell if it hasn’t done so already. It then extracts the customer Id from the specification (the event payload) and hands it to the ViewModel which should know what to do.
The last argument, “IsNotificationRelevant”, refers to another method of the coordinator. This is a “predicate” (a function taking one argument and returning true or false) that determines if the EntityNotificationEvent concerns a customer. If it concerns a customer, the subscriber cares and the EA should invoke the “NotifyView” handler. If the event concerns any other kind of entity, the subscriber does not care and the EA should move on to other subscribers.
The second argument, “ThreadOption.UIThread” tells the EA that it should only call the handler on the UI thread. Prism contemplates the possibility that you will raise the event on a background thread. By default, Prism calls handlers on the publisher’s thread. Were we to raise the EntityNotificationEvent on a background thread and not specified the ThreadOption, our application would explode in pain: our handler updates the UI and that must be done on the UI thread.
To be safe, I should have specified the UIThread in the earlier CacheClearEvent subscription. I happen to know for a dead-on certainty that the CacheClearEvent will never, never, never, never, never be raised on any thread other than the UIThread. I’ll never have a problem. We continue.
I saved the third argument for last.
The Prism EA can hold strong or weak references to your handler and filter functions (“NotifyView” and “IsNotificationRelevant”).
The references are weak by default … usually a wonderful convenience because it relieves the developer of concern about a memory leak.
Suppose the references were strong and the coordinator went out of scope by which I mean that there were no other living objects that held a reference to it. I would hope that the garbage collector would come along and remove it from memory.
Unfortunately, the EA would keep my coordinator alive because it would have a strong reference to the coordinator handler. My coordinator would live as long as the EA itself … which is as long as the application session itself. The coordinator, which is doing nothing for my application, is holding down a spot in memory. That’s the leak. I’ll have to take special steps (implement IDisposable, unsubscribe in the Disposing() method, remember to call Dispose) if I want to ensure that the coordinator gets garbage collected. I probably won’t bother.
Suppose the EA’s handler references are weak. Now the EA’s references to the coordinator “don’t count” and the garbage collector can dispose of it as soon as no other object holds a reference to it. I won’t have to write a lick of code. Pretty sweet.
So why did I force the EA to hold strong references by setting “KeepAlive” to true?
Trust me, I tried the weak reference first and there was a problem. A big problem. The coordinator was garbage collected BEFORE it had a chance to hear the first Customer notification event. In fact, it was collected almost immediately after it subscribed to the event. I never saw the “Customer Orders” tab let alone the customer/orders master/detail view.
Why? Because the coordinator was never referred to by another object with sufficient lifetime. I thought that the CustomerOrdersModule would keep it around but, oops, that instance was GC’d too! Apparently decoupling really works. It was a tough bug to track down too; watch for it.
Wrap Up
This is long post … with many a winding turn.
That worries me because it suggests that Event Aggregator is hard to use. It is not. The code to consume it, as we’ve seen, amounts to about 30 neatly spaced lines. So blame me for being long winded.
Try it yourself. Use it wisely … and sparingly.
Event Aggregator is appropriate when
- the subscriber shouldn’t know the publisher
- subscriptions can precede publications
- the Event is Fire-and-Forget
Do not use it everywhere. It is not a replacement for standard .NET eventing.
Update 16 June: The "Prism Explorer" code has changed. The "Coordinator" is now a "Screen Factory", it unsubscribes, and the "ViewModel" is now subscribing once it has been created.
The gist of this post remains true and relevant. There is still a GC threat to the "Screen Factory" which must subscribe with a strong reference. The changes were prompted by design interests unrelated to EA.
And ... yeah ... I guess you could say I changed my mind about whether the VM should subscribe. There was very little duplication, the Factory got simpler, less indirection ... hey, what more can I say?
Sunday, May 24, 2009
Birth and Death of M-V-VM Triads
A specter has been haunting my code of late. I’ve been calling it the “coordinator” although I’m not wedded to the name. I just know I need it. I need it because I need something to build my Model-View-ViewModel triads. I need something to coordinate them when they are closely related. And I need something to tear them down and dispose of them when they are no longer needed.
That’s my coordinator.
Some friends tell me they don’t see the need for such a thing. I’m not sure how they do without it. Maybe this post can initiate a clarifying discussion.
But first, a little throat clearing.
The Model-View-ViewModel (MVVM) pattern is on the lips of many a Silverlight and WPF developer. It’s ungainly name garners many jokes - the patty-cake pattern, the mumble pattern – but it survives them all. It is the predominant presentation pattern for these technologies and I can’t recall seeing serious discussion of any alternative; it is as close to a consensus heuristic as we get in this business.
There remains plenty to fight about under the MVVM tent.
- Is there any substantive difference between MVVM and Martin Fowler’s “Presentation Model”? If not, why coin a new (and uglier) term?
- How much code-behind in a View is “too much” and what makes it too much?
- When does the XAML devolve into a morass of fetid, untested, crypto-imperative code?
- Does the View (V) come first or the ViewModel (VM) ?
- Should VM have a reference to the V (via its interface of course) or should the VM be ignorant of the view in every way?
- How does the Model enter the picture?
- Is the Model (M) confined to the network of “business objects” presented in the view or does it encompass the mechanisms (e.g., persistence) which create, retrieve, and save those objects?
- Is the VM allowed to offer the V an unwrapped M-object (e.g., the raw Employee) ? Or must the M-object’s properties (if it is even permitted to have properties!) be exposed exclusively through the surface of a VM wrapper?
To pose such questions invites a fist-fight. Small wonder that many developers keep their distance from MVVM; whatever you do you’re doing it wrong.
Perhaps we could all grow up just a little. I’m not diminishing the importance of these differences; I am suggesting a change in conduct.
Sermon over … on to today’s topic: where do you create an MVVM triad and how do you get rid of it when the view is no longer wanted?
The triad doesn’t create itself. Something creates it and puts it in motion.
This isn’t much of an issue in simple applications. It becomes serious when you contemplate
- a screen or page constructed dynamically, perhaps in response to user action
- a composite page consisting of regions holding views, perhaps nested views, each implemented as MVVP triads
- a wizard
- closing a collection of views with a single click
There is significant logic here. Where does it go?
Permit me to indulge an example near to my heart. I have a sample Silverlight application that demonstrates how my company’s DevForce product plays well with Prism. It’s called “Prism Explorer” and you can check it out here. You can run it … and download the source later if you’re interested. Here’s what happens when you run it:
Prism Explorer presents a tab displaying a grid, some buttons, and a ComboBox with queries you can try. Some queries return Customers; some return Employees or Orders or a projection over Customers. There is a second tab that does the same thing … for reasons I won’t go into.
Now if you query for anything except Customers, the application’s responses are confined to the current tab. If you query for Customers, a new tab appears called “Customer Orders”. Click on that tab and, after a trip to the server, you’ll see a master/detail display of the current customer and its orders.
What’s happening? When the application launches, it starts up two modules. One drives the two querying tabs (the “Model Explorer View” module) and the other drives the “Customer Orders” tab.
This second module instantiates a CustomerOrdersCoordinator which just listens (via Event Aggregator) for a “Customer notification event”. It doesn’t display anything. When it finally hears such an event, it create the MVVM triad to display a CustomerOrders master/detail view.
As it happens, the ViewModel takes over the listening chores and updates itself whenever the selected customer changes. The ViewModel doesn’t waste time fetching customer information if it’s view isn’t visible … which is why there is a visible delay when you activate it’s hosting tab.
Thank you if you’ve stuck with me this far and for going along with my scenario. You will notice that the CustomerOrders view and its host tab are not immediately created. They appear only as a consequence of some application logic.
Clearly a ViewModel that doesn’t exist can’t be listening for events. I could have put the coordinator’s logic inside the module class itself. This teaches me nothing. All I get is a module class with an unusual section and unexpected responsibilities … which is why I factored out the Coordinator in the first place.
Confronted with this scenario, what would you do? Is there a need for a coordinator or is there some pattern I’m overlooking?
This is a blog post, not a master’s thesis, but a little literature review seems in order. Gang of Four is silent on these subjects. Martin Fowler’s Patterns of Enterprise Architectures is the next stop on the “Pattern Legends” tour. A landmark effort first published “way back” in 2003 it remains “venerable” in the best sense.
Fowler’s initial thinking was confined to HTML web presentation problems. He expanded the inventory in subsequent years through a series of posts that can be reached from here. The combined corpus of patterns still resonate for WPF and Silverlight developers even if the details aren’t a perfect fit for these more recent technologies.
Most of this material concerns ways to separate logic from the view - Model View Controller (MVC), Model View Presenter (MVP) in its two flavors – Supervising Controller and Passive View - , and Presentation Model (which I am unable to distinguish from MVVM).
As I read him, the collaborator in control (C in MVC, P in MVP, PM in Presentation Model, VM in MVVM) is not responsible for creation or destruction of the collaborating group (aka, the “triad”). Something outside of the triad has these responsibilities. What does that thing look like and, more importantly, what do we call it?
I find three candidates in Fowler’s pattern book: Front Controller (344), Page Controller (333),and Application Controller (379) all of them expressed in web-specific terms. Can we re-purpose them?
None of them deal with disposing of views because that is simply not an issue in the HTML web world. That shouldn’t stop us from augmenting one of them if it is a good match in other respects.
Front Controller is out immediately. It is a single server-side controller that maps incoming requests to commands which, when invoked, result ultimately in pages shown to the user. It has no role in composing the pages. It’s a traffic cop.
Page Controller is more promising once stripped of its obligation to interpret HTTP requests. It acquires the parts we want – Model, View (and, implicitly, the Controller behind the view) – puts them together, and let’s them go on their way. However, as Fowler describes it, this class is mostly about request routing; it’s essentially a simplified combination of Front Controller - which does no page composition at all – and Application Controller.
The Application Controller (379) seems to me to be the most apt pattern. An application controller takes input from an “input controller” and determines the matching “domain logic” and “view”. Fowler has a Front Controller in mind when he speaks of “input controller”; in a RIA application the input could be an event raised in response to a gesture. The application controller then chooses the right recipe and cooks the view to show the user.
My misgiving about this pattern is the sheer scope of its ambitions. In Fowler’s epigram it is a “centralized point for handling screen navigation and the flow of an application”. That’s a big job, especially in a large WPF or Silverlight application. I’m not convinced we should have a “centralized point” for the application as a whole. Perhaps it makes more sense to think this way at the module level which is where I see the most need for “the thing that composes views”.
And yet I remain uneasy. I’m thinking we need something a bit more focused on a smaller set of concerns. I just want something to build and tear down one or more closely related MVVM triads.
Jeremy Miller hints at this in his artful analysis of composite applications, the excellent (albeit unfinished) “Build Your Own CAB” series. I direct your attention to his last completed entry, “The Main Players”, where he talks about Application Controller.
The ApplicationController controls the screen activate lifecycle and the lifecycle of the main form. In most of my systems other screens are activated by calling methods on the ApplicationController. In smaller systems the ApplicationController would also control screen workflow. In larger systems I would break some of that responsibility out into separate collaborating classes.
This reasoning leads him to describe three kinds of subsytem collaborators, one of which, the “Screen Conductor”, captures my intention almost exactly:
[Screen Conductor] controls the activation and deactivation lifecycle of the screens within the application. Depending on the application, the conductor may be synchronizing the menu state of the shell, attaching views in the main panel or otherwise, and calling hook methods on the Presenters [read ViewModels] to bootstrap the screen. It may also be just as important to deactivate a screen when it's made the inactive tab to stop timers.
My applications tend to be modularized with the help of something like Prism. I wouldn’t have one Application Controller with one Conductor. I would tend to have one “Conductor” per module and I would launch it from within my module class.
I’m not a stickler for one-per-module either; let the circumstances guide you. On the other hand, a profusion of Conductors should give you pause; it suggests that your ViewModels are anemic and underperforming.
But Ward, you called your version a “Coordinator”? Shouldn’t it be called “Conductor”.
Maybe it should. It was a toss up when I was thinking about it and I had forgotten Jeremy’s taxonomy until I started this post. John Papa and I had a blast dreaming up names that keep the avalanche of M’s and V’s going. “ViewMotivator” had possibilities: MVVMVM
A rose by any other name …
Friday, May 22, 2009
A PixelShader that means business
Maybe you heard that PixelShaders are a feature of Silverlight 3 … which is coming our way very soon.
Maybe you’re like I was, thinking that PixelShaders have no place in a business application. Hey, I love those rippling water demos as much as the next guy. But I’ll be looking for new employment the morning after I give my application a psychedelic makeover.
Then my buddy Joe Gershgorin introduced me to the “Grayscale Effect”, a PixelShader effect that de-saturates the colors of the targeted image, “graying” it out.
You say “So what?”
Here’s a hint: What’s the look of a disabled button? It’s gray.
I used to have one image for the active button state and another image for the disabled button state. If I’ve got 10 buttons, that’s 20 images to maintain. That’s double the payload winging over the wire to my Silverlight client.
It takes time (and skills I lack) to produce the first image; adding a disabled version is another step I can do without.
Now, instead of swapping button images when the enabled state changes, I add or remove the grayscale effect.
I’m not sure where Joe found the code for this effect. The first mention I can find is a blog post by Anders Bursjöö from June 2008. I don’t know if Anders post was first; I can confirm that it will take you through the details of the effect as it relates to WPF … which details are the same for Silverlight.
There is no need for me to repeat what Anders had to say or the many who followed him and took their turns at explaining it. I can also recommend Greg Schechter’s series of May 2008 posts on custom GPU-based effects for WPF.
Now put that knowledge to good use by shedding image bloat and waste your creativity on some other project.
Oh … you wanted code?
Dude ... it's XAML. We'll be here all day.
Ok, here are two snippets for your delectation. Imagine we're inside ResourceDictionary defining a style for the button.
Here is the image definition that will use template binding to pick up the image assigned to the button:
<Image
x:Name="ImagePresenter"
Margin="0,0,0,0"
Opacity="1"
Source="{TemplateBinding Image}"
Width="32"
Height="32"
HorizontalAlignment="Center"
Stretch="Uniform"
>
<Image.Effect>
<effects:GrayScaleEffect DesaturationFactor="1"/>
</Image.Effect>
</Image>
Notice how we added the effect, setting the DesaturationFactor to one (meaning … ahem … no desaturation). GrayScaleEffect is the class straight from Anders example.
Now let's look at the pertinent "Disabled" state governed by the VisualStateManager:
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimationUsingKeyFrames
BeginTime="00:00:00" Duration="00:00:00"
Storyboard.TargetName="ImagePresenter"
Storyboard.TargetProperty="(UIElement.Effect).(GrayScaleEffect.DesaturationFactor)">
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Notice how we’re identifying the effect and its DesaturationFactor property using attached property syntax. Setting the factor to zero results in the gray effect. We’re not using animation so the duration is zero-time.
Wouldn’t it be great if there were a one-liner to specify a no-animation Storyboard or just to skip the Storyboard altogether? Maybe someday.
Saturday, May 16, 2009
My Prism TechEd ARCast
Denny Boynton cornered me at TechEd for an ARCast video. He got me to talk about Silverlight application development with Prism (like that was hard for me, right?).
Here’s the link: Building Modular Applications Using Microsoft Silverlight and WPF.
Saturday, May 2, 2009
Prism Event Aggregator Subscription Blues
After too many hours of debugging and hair-pulling, I finally figured out why my Prism EventAggregator (EA) subscriptions were not working in an important case. The reason made perfect sense ... once understood.
Here is the setup.
- I have a CustomerOrders module to manage viewing and editing of one Customer and its Orders.
- I have another module, CustomerSearch, in which the user searches for Customers.
- The two modules are de-coupled.
- The CustomerOrders module learns about which Customer to show when CustomerSearch publishes the SelectedCustomerEvent.
- The CustomerOrders module will not display itself until it hears the first SelectedCustomerEvent.
This is a canonical example of cross-module Eventing, perfect for Prism's EventAggregator.
Here is the subscription in the CustomerOrders module:
_eventAggregator.GetEvent<CustomerSelectedEvent>()
.Subscribe(NotifyView);
But the subscription is never raised and NotifyView is never called! The CustomerOrders module is instantiated alright but it never shows a Customer.
Maybe I didn't publish correctly. So I try subscribing inside some other class that I'm sure is in-use ... such as a class in CustomerSearch itself.
_eventAggregator.GetEvent<CustomerSelectedEvent>()
.Subscribe(HeardIt);
...
public void HeardIt(object dummy) {
var sink = "I heard you";
}
Put a breakpoint on HeardIt; works like a charm.
I break at the point where I'm adding subscriptions to CustomerSelectedEvent; they are all there! I can see both subscriptions in the CustomerSelectedEvent's list of subscriptions.
After a few frustrating hours, I happen to look at _eventAggregator subscriptions when HeardIt is called. Now there is only one, the one for HeardIt. The CustomerOrders subscription is gone!
Then I remember, EventAggregator holds weak references to subscriptions by default ... so the subscriber doesn't have to unsubscribe when it is disposed or garbage collected (GC'd). This is a very cool feature. Sadly, I immediately suspect that this is the source of my problem. To test that thesis, I force the subscription to use strong references.
const bool keepAlive = true;
_eventAggregator.GetEvent<CustomerSelectedEvent>()
.Subscribe(NotifyView, ThreadOption.UIThread, keepAlive);
It works!
Of course now the instance in which I make this subscription will hang around for the life of the application (the life of the EA to be precise). This is a potential memory leak. If I'm going to make and forget a lot of these instances, I better remember to unsubscribe, perhaps via IDisposable. That doesn't seem like fun.
Why did the subscriber disappear ... taking its subscription with it?
Prism decoupling was just doing its job. Most Prism modules that you will ever create actually disappear rather quickly.
You can verify that thesis. Drop the following in your module class (the inheritor of IModule) and set a breakpoint:
// Destructor to demo when GC'd
~MyModule() {
System.Console.WriteLine("Goodbye, MyModule");
}
If your module class is very simple as it should be ... perhaps some type registrations before dropping a view into a region ... you'll see that destructor called in no time; happens almost immediately for me because I'm running in a VM where the garbage collector is very busy.
So my subscription disappeared because I subscribed within a class that itself disappears ... really quickly.
In my example, I was unable to find or construct an instance of a class that outlived the module.
I could have put it inside the View (the ViewModel to be precise); once the View was injected into the visual tree, it would outlive the module because the visual tree would keep it alive. That is why the subscription to "HeardIt" worked in the CustomerSearch module . I had subscribed inside a ViewModel after it's companion View had been presented. It didn't matter that the CustomerSearch module class instance, which had created that ViewModel, had long since been GC'd.
Unfortunately, I can't follow that example in the CustomerOrders module. Can you see why?
Remember I said at the beginning that the CustomerOrders module waits for the first publication of CustomerSelectedEvent before it shows itself. If I don't show anything, everything I create in that module evaporates (get's GC'd) before the first publication of CustomerSelectedEvent!
I have to do something to keep the module around until it can do its work. I'm sure you can think of plenty of ways; I did. They're mostly ugly. I decided that I should put my solution near the cause of the problem ... and so I ensure that at least one subscription has "keepAlive = true".
I won't worry about the potential memory leak from hanging on to the module class; I don't expect to have more than one instance of this module in the lifetime of this application. I'll just document the issue and move on.
Hope this helps you!
p.s.: No ... I did not actually put this logic in the module class. Module classes are supposed to be bare bones. I put it in a Coordinator class, an instance of which is resolved by the CustomerOrders module. The problem is the same. The coordinator is referenced only by the module so it evaporates when the module does. I thought this detail would only interfere with exposition were it introduced earlier.