Sunday, February 08, 2009

Avoiding Login Dialogs with TFS Remote Access

I’ve been working on a project for a remote customer for a number of months and something that constantly bugged me is the way TFS wants you to log in every time you open your solution or fire up Team Explorer. Unlike other login dialogs in Windows and Internet Explorer, the one presented by TFS does not have the magic checkbox to “Remember my password”. But at some point I did something on one machine and it stopped asking and was logging me in automatically if I was online. Excellent! Now how to get it to behave the same on my other two dev machines?

I did a little thinking and realized that TFS just uses HTTP Web Services for it remote access. The team project I was working on was using SSL and a particular port, lets say it was 8089.

So I just fired up the browser, hit http://tfs.somecompany.com:8089 and I got the standard IE login dialog which does have the Save password checkbox. Checked that box, got and error of course because the web service is not designed to be used from the browser, but now whenever I hit the team project in VS through opening the source controlled solution or opening Team Explorer, viola it logs me automatically now.

10 seconds of effort on any machine to avoid the repeated hassles of logins. Nice.





Sunday, February 08, 2009 9:42:23 PM (GMT Standard Time, UTC+00:00)
Comments [1]  | 


  Sunday, January 04, 2009

Arabic-English Encyclopedia of Computer and Internet Terms

If you work with any colleagues who read and speak Arabic but are still getting up to speed on technical terms in English, you should have them check out a book written by a friend and neighbor of mine:

Encyclopedia of Computer and Internet Terms, by Dr. Alam E. Hammad.

It has the technical terms in English and the explanation in Arabic.

Should be a great reference for Arabic speakers to have handy.





Sunday, January 04, 2009 9:17:07 PM (GMT Standard Time, UTC+00:00)
Comments [1]  | 


  Friday, January 02, 2009

.NET Technical Forecast 2009

Beginning of the year is always a good time for reflection and speculation on what is to come, so I thought I would put a few thoughts out there on what the technical forecast for 2009 looks like to me. I'll do it in the context of some of the key technologies I work with on a regular basis.

WCF: Because this got great adoption from the outset, I don't see a huge change in the rate of adoption of WCF. What I do see is more and more use of the REST programming model that came available in .NET 3.5. Unfortunately, I predict that more people will end up using that model instead of SOAP-based messages than probably should, just because it has the hype right now. REST makes a lot of sense for externally exposed, resource-oriented services to put a minimum bar for consumption of data out there. For secure, reliable enterprise services though, you need the additional protocols that the WS-* stack gives you. Consumption of a SOAP based service is also still far easier due to simple code generation of the proxy. So internal services should still be using SOAP in my opinion, but REST makes perfect sense for public exposure of data, whether read only or read-write.

Cloud Services: With the Azure platform announced and PDC, the .NET Services piece of that which has been available for a while in CTP form in its previous incarnation as "BizTalk Services", third party vendors building lots of cloud-like services, expansion of the mobile application market with the explosion of iPhone and the chasing touch devices out there, cloud services will certainly grow in importance and early adopter attention, but since a released Microsoft variant will not come until possibly the very end of 2009 or early 2010, most production projects will probably not accept the risk of building against the platform for at least 6-9 months.

WF: One word: hesitation. WF has had very low adoption as it is because it requires a pretty significant shift in the way you think about designing your systems as well as how you go about that. Couple that with a number of rough edges in the programming model and the fact that you have to build a fair amount of infrastructure around your solution to run it effectively in production, and you can understand the slow adoption. It is still a vary rich platform for building complex business applications, but certainly can use some improvement. The good news is, that improvement is coming in .NET 4.0, in a big way. At an SDR I attended in the Spring of 2008, I commented to one of the product team members that I was very pleased because they were fixing or improving every single aspect of the WF model that causes difficulty for me or my customers with the current version. The bad news is that to do that, they are making some pretty sweeping changes in the programming and even hosting model of WF. That doesn't mean that you will have to rewrite anything you build today, there is an easy interop story to run 3.5 workflows and activities in the 4.0 model. But it does mean that if you start building on 3.5 now, you will have to learn a set of skills that you will then have to relearn in about a year to start building things the new way. It is not 100% relearning of course, but the changes are sweeping enough that I would guess that 60-70% of the time you spend on the workflow part of your application will be done at least slightly differently in 4.0 than in 3.5.

WPF: Adoption should start to take off more than it has in 2008 due to a combination of factors. One of the impediments are the tools, and those are not going to change substantially until VS 2010 comes out (don't know if that will be its name, but it is reasonable speculation to guess that). However, a bigger impediment has been the learning curve, and having companies willing to bite the bullet to acquire those skills. Competitive pressure, both for the companies and the developers themselves, will continue to mount quickly though as more companies ship nice looking WPF apps that demonstrate the ways you can substantially alter the user experience by using WPF. That will help force people to learn the WPF way of doing things to stay competitive. The other factor is Silverlight adoption. With rapidly growing interest and adoption of Silverlight, companies will quickly realize that the skills investment in either WPF or Silverlight cascades to a large degree into the other technology, so that will allow them to build the best kind of app for their users without needing to master two completely different UI skill sets. And finally of course, the closer we get to better tools, the shorter the period of productivity hits you will have to endure by being on WPF, so that barrier becomes less as well.

Silverlight: Although there have been some media hits with a public announcement of dropping Silverlight, there have been many more success stories out there due to Silverlight 2, and I think people are really seeing the light there. Some stuff still belongs in web pages and web forms. But for rich interactive applications that are web delivered, you can't beat Silverlight as a platform when you are a .NET developer. Add to that all the cool new stuff coming to enhance Silverlight development in .NET 4 and VS 10, and you have even more reason to make this a first consideration for any interactive web application. The only caution is similar to what I said about REST services. Don't overuse Silverlight just because it is the shiniest new toy. WPF or Windows Forms smart client apps still make sense for a broad assortment of internal corporate type applications.

Economic impacts: OK, the market sucks and we are all feeling the impacts in one way or another. But the fact is that the world already runs on software. And short of a total global economic collapse, we can't stop making or at least maintaining software. So I think there is room for plenty of work in our sector even if things get bad. And if you can align yourself with markets that are doing well, then you should be able to weather the storm.

So that is about it. Nothing too startling or earth shaking there. But a view through my eyes based on what I see from working with lots of customers around the globe.





Friday, January 02, 2009 3:32:24 PM (GMT Standard Time, UTC+00:00)
Comments [1]  | 


  Friday, December 19, 2008

Cloud messaging made easy with Linxter

Want to allow different applications to communicate over the Internet without requiring any service infrastructure of your own and without needing to learn and understand the complexities of WCF? There is now a solution that you might want to take a look at.

I've been working with a company called Linxter helping them build out a cloud messaging infrastructure that makes building cloud-connected applications even easier than building them using WCF. Basically they have set up the infrastructure and provided an easy to use SDK that encapsulates all the scary code required to really do reliable messaging over the internet, while supporting occasionally connected scenarios, security, reliability, and other aspects.

Basically all you do is download the SDK, add a reference to a single DLL, run a tool to generate a supporting database (file based, SQLite), and start making calls.

The API is really simple, you just call CreateMessage to send a message, subscribe to an event to know when you have received a message, and there is a one time step to register your program instance with the back end Linxter Internet Service Bus (ISB) infrastructure.

So a simple Hello World app could look something like this:

// The API is separated into three interfaces focused on 
// the three aspects of using the SDK 
ILinxterMessaging messaging = new LinxterSDK();
ILinxterRegistration registration = messaging as ILinxterRegistration;
ILinxterCommunicationChannel commChannels = messaging as ILinxterCommunicationChannel;

// Subscribe so received messages raise an event
messaging.MessageReceived += OnMessageReceived;

// One time step in the life of a program instance - register
registration.RegisterProgramInstance();

// Tell the SDK to start retrieving messages based on a configurable schedule
// On demand also supported
messaging.StartScheduledReceive();

//  Create a channel to another instance based on an ID or alias name
ProgramInstanceInfo responder = 
    commChannels.FindProgramInstances("HelloWorld Responder", 
    FindProgramInstanceType.ByAlias)[0];

commChannels.CreateRequest(responder, "Invitation message");
// Send on demand or on schedule supported
messaging.SendNow();

// Wait for channel to be opened to the receiver
while (!IsOpenCommunicaitonChannels(commChannels, responder))
{
    Console.WriteLine("Waiting for comm channel creation");
    Thread.Sleep(1000);
}

// Construct a message to send to the receiver, can be many
List<Guid> receivers = new List<Guid>();
receivers.Add(responder.ProgramInstanceId);
// Each message can have an activity ID to separate different message types
string activityId = "b9501157-be9a-4a98-aab6-1c1e17ac8d99";

// The message body is simply a string 
// (in which you can encode whatever data you want, however you want)
Guid msgID = messaging.CreateMessage(receivers, activityId, "Hello World");

// Messages are always queued in the client DB supporting offline scenarios well
messaging.SendNow();

 

Then of course you need the event handler that receives the messages:

static void OnMessageReceived(MessageReceivedEventArgs e)
{
    Console.WriteLine("\nNOTICE: Message Received: {0}", e.Body);
}

There is a lot more to it of course, but the point is that you can integrate Linxter into just abobut any kind of .NET program including smart client applications, web applications, and Windows services. You don't have to learn anything about how to get the distributed messaging done, they have done all the work for you.

Eventually there will be support for using Linxter in other platforms, so it can form the glue to integrate applications from different platforms.

Of course you could do these things yourself with WCF and .NET services, but to do it that way you would have to master a much more demanding set of skills and may have to set up some infrastructure of your own. With Linxter, you just need a reference to a library, a few method calls into that library, and an account and your applications can be connected really quickly.

If you want to learn more, you can visit the Linxter Developer site at http://linxterdeveloper.com. You can download the SDK and QuickStarts there as well.

Linxter should be releasing version 1.0 by early 2009, so that is another advantage for the near term compared to building it all yourself with WCF and .NET Servicces.

Check it out and you can give me any feedback, which I can pass along to the development team.





Friday, December 19, 2008 1:26:31 AM (GMT Standard Time, UTC+00:00)
Comments [1]  | 


  Thursday, November 13, 2008

Visual Studio Connections Slides and Demos

I gave three talks at Visual Studio Connections in Las Vegas this week:

  • Selecting the Right Client Technology
    • This session summarized the capabilities, pros, cons, and influencing factors for deciding between smart client or web, WPF, Windows Forms, ASP.NET, Silverlight and Mobile. It also summarized the client software factories and guidance from Microsoft p&p at the end.
  • Leverage Routed Events and Commands in WPF
    • This session covered how routed events and commands work in WPF, how to hook them up, how to handle them, how to implement custom commands, and best practices for employing them.
  • Developing Service Oriented Workflows
    • This session covered building workflow services with WF and WCF. It covered the Send and Receive activities, context bindings, and Workflow Service Host. I showed using workflows as a business process orchestration that calls other services, multiple clients calling into the same workflow, implementing custom send activities to overcome the limitations of the built-in Send Activity, and calling between workflow instances.

You can get the slides and demos for all these sessions here.





Thursday, November 13, 2008 7:27:38 PM (GMT Standard Time, UTC+00:00)
Comments [1]  | 


  Sunday, November 09, 2008

The Truth about Routed Commands Routing

In my article on Routed Events and Commands in the September MSDN Magazine, I made a quick reference to a very subtle, confusing, and misunderstood aspect of how routed commands are actually routed. It was only a brief reference because it was only made clear to me through some excellent tech review feedback from the Product Team (thanks Dwayne and Varsha!) a couple days before going to print, so I couldn't add a big explanation without trashing the print flow for the magazine.

I had a question from a reader who is a well known WPF expert himself, so I figured I'd better expand my explanation.

The short simple answer if you don't want to understand all the complexities of what is going on under the covers is this: Always put your command bindings on the root element (Window or Page) and your command binding will always be consulted. You can do this explicitly in the XAML, or you can inject it there through CommandManager.RegisterClassCommandBinding.

But if you want to deviate from that guidance, you really have to understand the following.

With WPF routed commands, routed events are used under the covers to dispatch calls to the command handlers both to determine when the command should be enabled, and to invoke the handling for that command when the command is invoked. For example, if I have a Save button in a toolbar, and I have a command binding at my Window root level, a routed event will be used to ask the CanExecute method of that binding if the button should be enabled. And then when the user clicks it, a routed event will be used to call the Executed method of the command binding.

Where things get confusing is if you try to place that command binding somewhere deeper in the visual tree because you have to have a good understanding of where the routed events are started and where all they flow to.

There are a lot of people that believe (myself included until Dwayne and Varsha from the product team showed me the light) that the routed events for commands flow from the focused element to the root of the visual tree with tunneling and bubbling events. That is really only a part of the picture.

The fact is that the routed events for a routed command ALWAYS are initially raised on the command invoker or source control, not the focused element. Any control that implements the ICommandSource interface can be a command source. This includes buttons (and checkboxes... anything deriving from ButtonBase), menu items, hyperlinks, and input bindings (i.e. keybinding) out of the box in WPF. These events follow the standard pattern for routed events in WPF - a tunneling event is routed down the visual tree from the root  to the target and then a bubbling event is routed up the visual tree from the target back to the root.

The focused element in the UI only gets the events routed to it if the command source is contained in a focus scope (the Toolbar). When that is the case, as the bubbling event reaches the focus scope boundary, the event is re-raised on the focused element.

So what is a focus scope? A focus scope is any container element that sets the FocusManager.IsFocusScope attached property to true. Toolbars and menus have this property set, so those are the main focus scopes you will deal with other than a Window or Page which is always the root focus scope, but you could easily create your own by setting that property to true on a container control.

So in my Save button example above, the flow looks like this when the button is clicked:

  • CommandManager.PreviewExecuted tunneling event raised on the Save button in the toolbar. This means it starts at the root element of the visual tree and tunnels down to the Save button through whatever element tree is in between.
  • CommandManager.Executed bubbling event raised on the Save button in the toolbar. This means the bubbling event flows from the button up to the root element of the Toolbar.
  • CommandManager.PreviewExecuted tunneling event raised on the focused element in the root UI.
  • CommandManager.Executed bubbling event raised on the focused element in the root UI.

To make it even more concrete, I wrote a little form whose element tree looks like this with several sources of the Cut command:

<Window x:Class="CommandFlow.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <DockPanel>
        <ToolBar DockPanel.Dock="Top" Height="30">
            <Button Width="75" Height="25" Command="Cut">Cut</Button>
        </ToolBar>
        <StackPanel>
            <Button Width="75" Height="25" Command="Cut">Cut</Button>
            <TextBox Width="150" Height="25"/>
        </StackPanel>
    </DockPanel>
</Window>

I then added attached event handlers for the PreviewExecuted and Executed events to each element in the tree and did a Debug.WriteLine so it would be very clear where the Executed events were flowing. I then ran it, put the focus in the Textbox, and clicked the button in the toolbar. The result is below.

Window Preview  Executed Called
DockPanel Preview  Executed Called
Toolbar Preview  Executed Called
Toolbar button Preview  Executed Called
Toolbar button  Executed Called
Window Preview  Executed Called
DockPanel Preview  Executed Called
StackPanel Preview  Executed Called
Textbox Preview  Executed Called

As you can see, a tunneling (Preview) event works its way down from the root element to the Toolbar button that is the command source, followed by a bubbling event back up. The important thing to notice here though, which is where the confusion about how  the focused element is involved, is that the bubbling event seems to have stopped after firing on the toolbar button, and then a new tunneling event is raised which tunnels down to the Textbox and ends.

What is happening is that the Toolbar is actually handling the bubbling Executed event (Handled = true), which stops the bubbling process. The CommandManager then re-raises the event on the focused element (Textbox) and a Preview event tunnels down to it. The Textbox has an internal handler for the Cut command, so that is why nothing bubbles back up from there.

WithFocusScope

If that wasn't confusing enough, you then also have to look at what goes on for command enabling. The CanExecute part of ICommand has a similar pair of tunneling and bubbling events that fire. They too always get raised on command source controls first. These events are triggered by things that change the focus of the UI. If there is more than one command source, each one gets consulted in turn. Then the path to the focused element in the UI gets consulted. Below is the sequence of events after the UI is up and idle, then I click in the Textbox to set the focus there.

Window Preview Can Execute Called
DockPanel Preview Can Execute Called
StackPanel Preview Can Execute Called
Window button Preview Can Execute Called
Window button Can Execute Called
StackPanel Can Execute Called
DockPanel Can Execute Called
Window Can Execute Called
Window Preview Can Execute Called
DockPanel Preview Can Execute Called
Toolbar Preview Can Execute Called
Toolbar button Preview Can Execute Called
Toolbar button Can Execute Called
Window Preview Can Execute Called
DockPanel Preview Can Execute Called
StackPanel Preview Can Execute Called
Textbox Preview Can Execute Called

So the bottom line to me is this: it is very difficult to explain and understand where the events are flowing in even a simple UI, let alone a very complex one. Trying to rationalize that in your development process to put command bindings anywhere except on the root element is the path to command routing hell. You are better off just always placing your command bindings on the root element, or if you don't want to do that, consider using Prism Commands which get the handlers decoupled from the visual tree and the focus. If you are a control developer, and you need to handle commands (such as Cut) that are inherently coupled to whether your control has the focus, then putting command bindings in your control will also make sense.

I hope that helps to clarify the magic that is happening under the covers of routed command routing.





Sunday, November 09, 2008 3:40:57 PM (GMT Standard Time, UTC+00:00)
Comments [2]  | 


  Monday, October 13, 2008

Composite Extensions for Windows Forms

Have you by chance looked at the cool stuff we produced for Composite Application Guidance for WPF (aka Prism), and wished you could have the same capabilities for Windows Forms, but without needing to adopt CAB/SCSF? Now you can get at least part of those capabilities.

When we were drawing to a close on Prism 1, there were certain things that we would have liked to do, but had to skip to stay within scope and schedule.

One of those things was that we realized that a lot of what we had come up with could be used in Windows Forms as well. Specifically, our module loading, events, and UI Composition patterns could all be used in the context of a Windows Forms application with just a little more effort. For those things that we knew were more general, we at least factored them out to a separate library, Microsoft.Practices.Composite. Alas, that is as far as it went because our charter was for WPF, not Windows Forms.

So I have been trying to find time to complete the work needed to use the non-WPA capabilities of CAL in Windows Forms and finally found a chunk of time at 37K feet on a trip to get it done.

For now I've created these as a stand alone set of libraries that you can add into your own solutions. Feel free to take the code, change the namespaces, etc. Eventually I'll integrate the capabilities into the CompositeWPFContrib libraries so it will be accessible there as well. What I added includes the following:

  • A SimpleUnityBootstrapper base class that removes the dependence on WPF and which removes the parts that create the Shell and Region related stuff. Regions in Prism were implemented in a way specific to WPF, and the CreateShell override in the UnityBootstrapper that comes with Prism expects you to return a DependencyObject, which is also a WPF base class. The SimpleUnityBootstrapper makes it so you can follow the same bootstrapping process as a WPF Prism application to get the container, module, and event services registered and ready to go.
  • A CompositeEvent class and supporting classes that allows you to have the same programming model and infrastructure as Prism loosely coupled Pub / Sub events, but this class supports UI thread dispatching to either Windows Forms, WPF, or any SynchronizationContext aware subscriber. If you are not familiar with the SynchronizationContext class, it came in with .NET 2.0 and provides a standard thread dispatching mechanism that is used by both WPF and Windows Forms under the covers. You can also create custom synchronization contexts for other places that you have thread affinity. If you want to see an example of a custom SynchronizationContext, check out the unit tests. I needed to write a mock SynchronizationContext to verify the dispatching worked correctly.
  • A sample application that shows a way to get a Prism Region-like capability to inject views into the shell.
  • Unit tests for all the supporting library code, most of which were blantantly adapted (mostly direct copy/paste) from the unit tests of Prism since I was trying to create something with pretty much the same API and the same behavior as the Prism counterparts.

I'm not going to pick apart the implementation here unless demand is great enough, but you are welcome to dig into the code in the source.

However, the point was to make it easy to have modular loading and loosely coupled events in a Windows Forms application. So let me show you the use of these capabilities in a sample application. The app itself is very simple, just a drop down list of products and a save selection button to simulate a save operation.

The app, in all its stunning UI glory, looks like this:

AppGrab

The combobox and button are part of a view loaded up by a module, which is loaded through the standard module enumeration and loading services in Prism. When the button is pressed in the view, its ViewModel fires a pub/sub event, which the shell subscribes to and updates the status bar. The view is a Windows Forms user control that I was able to add dynamically to the shell using a simple form of region based on resolution through the container.

So the derived bootstrapper class from the SimpleUnityBootstrapper base class looks like this:

internal class Bootstrapper: SimpleUnityBootstrapper
{
    protected override void ConfigureContainer()
    {
        base.ConfigureContainer();
        Shell = Container.Resolve<Shell>();
    }
    protected override IModuleEnumerator GetModuleEnumerator()
    {
        return new StaticModuleEnumerator().AddModule(typeof(CompositeWFModule));
    }

    public Shell Shell { get; private set; }
 
}

I used the override of ConfigureContainer (same purpose as the UnityBootstrapper ConfigureContainer method) as a convenient place to construct the shell through the container, so that it can participate in dependency injection. This is an alternative approach to the CreateShell override that is required in the UnityBootstrapper of CAL, which is needed in CAL because the base class uses WPF Dependency Properties to add the RegionManager reference as an attached property to the shell after its construction. Since we are in Windows Forms land, that approach won't work, so regions don't exist in my modified libraries, but my sample app shows a way to achieve a lightweight form of dependency injection based on the shell being available through the container.

For module enumeration, you can see that I am just using the StaticModuleEnumerator that ships with CAL. All that is really needed to take advantage of the modular loading capabilities of CAL is a suitable bootstrapper base class that doesn't assume you are in WPF land. Thus my SimpleUnityBootstrapper class.

The Shell property is exposed to make it easy to get the shell to pass to Application.Run in the program's main method:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Bootstrapper bootstrapper = new Bootstrapper();
    bootstrapper.Run();
    Application.Run(bootstrapper.Shell);
}

To create a similar capability to Regions for view injection in the Shell in Windows Forms, I simply have the shell register its containers that it wants to act as a region with the container so they can be resolved by the modules that load up:

public partial class Shell : Form
{
    int m_UIThreadId = Thread.CurrentThread.ManagedThreadId;

    public Shell(IUnityContainer container,IEventAggregator evtAggregator)
    {
        InitializeComponent();
        container.RegisterInstance<Panel>("MainRegion",m_MainRegionPanel);
        evtAggregator.GetEvent<ProductSavedEvent>().Subscribe(OnProductSaved,
ThreadOption.SubscriberAffinityThread); } void OnProductSaved(Product p) { Debug.Assert(Thread.CurrentThread.ManagedThreadId == m_UIThreadId); m_StatusLabel.Text = p.Name + " saved"; } }

Notice that the shell is able to have the container and the CAL event aggregator service injected as dependencies because it was constructed through the container itself (in the bootstrapper shown earlier). It then registers the existing instance of a container control with the container as a named instance (MainRegion in this case) so that a loading module can resolve that named instance to know where to add its views as children.

Ignore the event subscription code for now, I'll get back to that.

The solution has a module library with a module class in it following the patterns of Prism and using the CAL IModule interface definition.

public class CompositeWFModule : IModule
{
    IUnityContainer m_Container;
    public CompositeWFModule(IUnityContainer container)
    {
        m_Container = container;
    }

    public void Initialize()
    {
        Panel mainRegion = m_Container.Resolve<Panel>("MainRegion");
        ModuleView view = m_Container.Resolve<ModuleView>();
        view.Dock = DockStyle.Fill;
        mainRegion.Controls.Add(view);
    }
}

Here you can see how the module injects the view into the pseudo-region. It just resolves the region out of the container with a known container type (yes, you do have to live with some type coupling here, at least to the minimal common denominator base class Panel), and once it has that, it just adds the view as a child control. For  more advanced scenarios such as adding tabs to a tab control you would need more type information to add the child, activate it, set the tab text, etc., but you could still be reasonably loosely coupled to where that control exists in the UI and how it gets constructed.

That is about it for the module loading and a lightweight substitute approach for regions in Windows Forms.

Then the real thing I wanted to get working for Windows Forms is Prism's loosely coupled pub/sub events model. This took a little more work simply because we tied ourselves a little too tightly (in my opinion) to WPF when implementing the UI Thread dispatching option for events in Prism. Both WPF and Windows Forms actually share a common approach to UI thread dispatching under the covers - SynchronizationContext. They both use it a little differently and encapsulate it so you can't directly get to it through their API, but since Windows Forms 2.0, that is available under the covers and in WPF that is what the DispatcherObject base class of UIElements is using to dispatch things to the UI thread.

So what I wrote was a more generic approach to UI thread dispatching under the covers of the CompositeEvent class (following the patterns of the CompositeWpfEvent class in CAL). The dispatching approach checks to see if the subscriber has a synchronization context, and if so, captures it and uses it to dispatch the event back to the UI thread through the SynchronizationContext when the event is fired if the subscriber asked for the event to be dispatched on the "SubscriberAffinityThread" (the name of the ThreadOption enum member I came up with.

I didn't want to call it UIThread because the pattern is actually more general than that. You can create your own SynchronizationContexts with a little work (in fact, I had to do just that to write a mock for the SynchronizationContext to test the code I was writing), and you might do that for specialized scenarios. For example, say you were going to be doing some background work in your app, you wanted to have a custom thread pool of 5 threads, and those threads had thread affinity (i.e. using ThreadLocalStorage). In that case, you could implement a thread pool synchronizer (see the example Thread Pool Attribute in our downloads at IDesign) that would ensure that there was a SynchronizationContext to dispatch to the appropriate thread. In that case, the CompositeEvent class I came up with will properly dispatch based on that SynchronizationContext instead of just a UI one.

So anyway, it is way more complicated to try to explain it than it is to use it. It follows the same simple but powerful patterns and capabilities as the CAL event.

To define an event type, you just derive from my CompositeEvent class instead of the CAL CompositeWpfEvent class, specifying the strongly typed event argument or payload as the generic type parameter:

public class ProductSavedEvent : CompositeEvent<Product>
{
}

To subscribe, you have the single line of code shown earlier in the shell constructor which points to the handling method (strongly typed based on the event argument type:

evtAggregator.GetEvent<ProductSavedEvent>().Subscribe(OnProductSaved,           
ThreadOption.SubscriberAffinityThread);

 

In this case I show the overload that just specifies the threading option, but just like the CAL events, this one supports the same three options in addition to just loosely coupled pub/sub:

  • Weak references or not for the subscriber object to avoid holding the subscriber object alive if the subscription is the only thing keeping it alive
  • Thread dispatching option for the notification
  • Filter delegate based on Predicate<T> to allow strongly typed decision based on the event payload to determine if your subscriber should be called or not.

The publisher code, in this case in the view being loaded up from the module, is just a single line of code like in CAL:

 evtAggregator.GetEvent<ProductSavedEvent>().Publish(product);

So there it is. If you have no exposure to Prism, you really need to start there, because I am not going to try to duplicate all the documentation on the capabilities of Prism. But once you are comfortable with the capabilities of Prism for WPF, now you have some code that will let you directly repeat the use of modules and events from Prism in a Windows Forms application with the exact same patterns, and you also have an example of how to pull off a "Region-like" capability using the IoC container and container controls in Windows Forms.

Feedback highly welcomed. I want to get any needed changes in there before I add it to the trunk for CompositeWPFContrib.

Here's the goods.





Monday, October 13, 2008 2:31:58 AM (GMT Standard Time, UTC+00:00)
Comments [4]  | 


  Saturday, October 11, 2008

SDC Day 2 - Composite WPF and WPF Data Binding

Gave two sessions on the second day at the Software Developers Network conference (aka SDC) in Netherlands.

First was on Prism (Composite Application Guidance for WPF). I covered the architecture of a Prism app and each of the features of Prism (Modules, Regions, Composite Commands, and Composite Events).

You can grab the slides and demos for Developing Composite Applications with Prism here:  Slides   Demos

Second session was on WPF Data Binding, where I showed the many capabilities and how to use WPF data binding.

You can get the slides and demos for WPF Data Binding here:  Slides   Demos





Saturday, October 11, 2008 10:58:00 PM (GMT Standard Time, UTC+00:00)
Comments [0]  | 











Ads by Lake Quincy Media









Sign In
Copyright © 2006-2007 Brian Noyes. All rights reserved.
Advertise on this site through Lake Quincy Media
designed by NUKEATION STUDIOS