This part 5 of my 6 part series on the EditingContext.
In this post, we’re going to tie together a few of the things we’ve seen in the last few posts and show how we can wire up parts of the designer (or the hosting application) to changes made to the Items collection of the EditingContext to do some interesting things.
You will note that both the ServiceManager and ContextItemManager have Subscribe methods, and I’ve talked in previous posts about how the publish mechanism is a little different. I want to dive a little deeper into how these work, the different overloads, and what you can expect have happen on the subscribe side of things.
On service, there are two different publish methods. I will list all four, and then talk about how there are really only two :-)
There are really only two methods here, and some generic sugar for the other two. They are Publish(Type, PublishServiceCallback), and Publish(Type, Object). If you were to look at the implementation of the generic versions, they simply turn around and call the un-generic form.
The difference between the basic one (Publish(Type, Object)) and the version with the callback is that the callback enables us to be a little more lazy and wait to actually create the instance of the object until it is first requested. Let’s look at how PublishServiceCallback is defined:
public delegate Object PublishServiceCallback(
Let’s now look at the subscribe methods. Again, here there are two methods (generic and non-generic), but they both do the same thing:
Both of these use a SubscribeServiceCallback defined as the following
public delegate void SubscribeServiceCallback(
This allows any consumer to be notified when a service is initially published. This is an important distinction we will call out versus items which provide a more advanced subscription method (namely, to changes).
Generally we find this useful for a few reasons:
Now let’s talk about Items:
Items do not have a publish method, per se, but they have the SetValue method which basically publishes an instance to the context. The semantics of SetValue are that it will first attempt to store the new value. Provided that succeeds, we then call OnItemChanged on the ContextItem itself. This is basically notifies the object itself (giving it a chance to react, clean up, or throw if something is really wrong). If this throws, the old value is preserved. If this succeeds, we then notify anyone who has subscribed to the changes.
GetValue allows me to retrieve the ContextItem. There are two GetValue’s, one generic, the other non-generic, but with a type as its parameter. It is important to note the point that is also present in the docs. If there is not an item present when this is called, the default value will be instantiated and returned.
Provided items are written using SetValue, all of the subscribers will be subsequently notified. If I just do an arbitrary GetValue and then make a few changes without calling SetValue, by default nothing interesting is going to happen (that is, no subscribers will be notified, subsequent calls to GetValue will get the updated object however). Subscribe (and it’s generic counterpart) allow me to provide a SubscribeContextCallback which will be invoked whenever SetValue is called. This functions basically in the same way that it does for Services.
An interesting pattern for Items that we use in a few places throughout the designer is to create an AttachedProperty on the modelItem (similar to this post) which in the implementation of the Getter and Setter will call out to the editing context to get or set the value from a ContextItem. This gives me a WPF friendly binding surface (foo.Bar binding syntax) that we can wire up to be change aware. We do this for a number of our triggers within our style implementation for things like is selected, etc. Future post note for me is that I should go through all of the attached properties present on a ModelItem that you could use to bind to :-)
This wraps up a tour of the Subscription / Notification engine present within the EditingContext.
Thanks for another great blog post Matt.
I understand that a service can be made available at any time, not necessarily during initialization.
Once a service is made available, should it be available for the entire lifetime of the host? If not, I take it there is
no way to be notified when the service is going 'offline'?
There is no way to "unpublish" a service, so you can assume the service will always be available. If you want to get a clean service manager, the best thing to do is to load a new instance of the designer.