• Shortcuts : 'n' next unread feed - 'p' previous unread feed • Styles : 1 2

» Publishers, Monetize your RSS feeds with FeedShow:  More infos  (Show/Hide Ads)


Date: Wednesday, 28 Jan 2009 21:39
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Sunday, 02 Nov 2008 03:50
I think we have conflated several concepts with RoutedCommands:

1)  The ICommand part with it's Execute/CanExecute methods ... basically this is just a form of method dispatch that lends itself to declarative systems
2)  Common Verbs or Actions -- these are what we now call built-in commands
3)  The mapping of basic InputGestures (Ctrl-C) to these Commands, the InputGesture collection on RoutedCommand


To understand this, imagine for the moment that we had a slightly different design.

First, we define something called Verbs.  A Verb is just a thing with a name, like "Paste", it almost could be a string, but type-safety is nice.  In this design we would have ApplicationVerbs.Paste instead of ApplicationCommands.
PasteCommand.  These could also be called Actions or Intents (and I have another name I'll reveal below).

Second, we define a way to map Verbs to ICommands.

class VerbBinding
{
     public ICommand Command { ... };
     public Verb Verb { .... };
}

Any UIElement could define VerbBindings just like they can CommandBindings and InputBindings today.    

Third, we have ways to map input to Verbs. 

class InputToVerbBinding
{
   public InputGesture InputGesture { ... };
   public Verb Verb { ... };
}

These could be defined "globally" in the input system, or scoped to tree elements.

In this design, the View maps basic input like keystrokes and mouse and touch gestures (all InputGestures) either to ICommands directly on the ViewModel or maps them to generic Verbs like Copy and Paste.  Verbs in turn act like input and route through the visual tree until they find a Binding that maps them to a ICommand on the ViewModel.  Imagine we had a VerbBinding which took Verb and an ICommand and called execute on the ICommand whenever the Verb was handled.  So for example, a menu might contain Verb="ApplicationVerbs.Paste" and there would also be a default key binding that would map Ctrl-V to ApplicationVerbs.Paste and the developer might also decide to map TwoFingerTouch to ApplicationVerbs.Paste.  Whenever the menu was hit or the Ctrl-V key was pressed, the PasteVerb would be fired and route just like input until it was handled by a VerbBinding and directed to the ViewModel.   (One nuance is that TextBox and other controls may also handle common Verbs like Paste...but let's set that aside for a moment). 

If you squint at this design, you start to realize that Verbs act just like InputGestures.  And funnily enough if you look in the input system you find we already have precedence for taking one input event and turning it into another one:  we turn Stylus input gestures into Mouse gestures so that applications that are not specifically programmed to handle a Stylus will still work.    Similarly, in the future we will cause dragging a finger across a touch screen fire not only TouchMove but MouseMove gestures so that apps written before Touch was supported will still work (with limitations).  So InputToVerbBinding could just be a way to extend the input system to map one set of InputGestures to another generically.  More abstractly, if we introduce a Touch gesture that means Paste, if the system just adds a global InputToVerbBinding, then any app that handles the Paste Verb will be future proofed.

Hmmm...does that mean Verbs are just InputGestures?  I mentioned I had another name for Verb in mind.  How about "AbstractGesture"? AbstractGesture would just be a peer to KeyGesture and MouseGesture (lousy name though...VerbGesture?).  If Verbs are InputGestures, then we no longer need a special VerbBinding, InputBinding is sufficient.  I also mentioned that there was a nuance that controls need to handle common Verbs.  Well, controls can handle InputGestures and if Verbs are a type of InputGesture...so we're done.  Alternatively and more abstractly, TextBox can be thought of as a ViewModel for a string property on your model...but I don't blame you if your head starts spinning now.

In the final design, we get rid of RoutedCommand and add a new sub-class of InputGesture called Verb.  CommandBinding goes away in favor of reusing InputBinding.  The InputGesture property of RoutedCommand is replaced by a new input extensibility that allows us to map one InputGesture to another.  ApplicationCommands, EditingCommands etc. become collections of common verbs and their default mappings from other InputGestures.  I'd probably invent a new thing like the InputToVerbBinding I mentioned, but I don't have a good name for it.

Feedback appreciated.
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 17 Oct 2008 05:30

I'm often asked about the Expression architecture, but have never found the time to really describe the whole thing.  Now Paul Stovell has dug into how it works using Reflector and compares it to Composite WPF (Prism).  Some of what he sees is a case of convergent evolution, though we did talk to the Prism guys at various times, and I think we had some influence. 

http://www.paulstovell.com/blog/expression-framework-versus-composite-wpf

 Paul wonders why we didn't use an IOC container.  For one simple reason, when we started there were no general IOC containers for .NET.  I also remain suspicious of "advantages" of an IOC container like support for circular dependencies, and like the simplicity of just using a heirarchy of strongly typed objects with properties and carefully managing your dependencies.  As Paul theorizes, the IApplicationService is really easy to use because Intellisense and auto-completion works 99% of the time.

 It's strange to see people looking at IAddIn and AddInManager.  I wrote that in 1 hour, 6 years ago, so we could run our test harness within our process.  As far as I know the code has never changed (other than somebody renaming it to AddInService...).  Warning to everyone who is looking at building Expression AddIns:  none of the internal APIs are intended for anything beyond running the Expression tests and they *will* change with every release.  We considered removing before we shipped, but it didn't seem worth it because of the disadvantage of not being able to run our tests against the shipping version.  Another Expression secret is the -diagnostics command line flag, which brings up internal perf and test tools.  We could have removed those too, though I like being able to diagnose problems on customer machines.

 If you read Paul's article and wonder how Model-View-ViewModel fits with the architecture described, remember M-V-VM is a UI composition pattern.  A lot of the stuff described is not UI specific, or if it is, can be considered to be the "Model" of Expression.

ps -- There's a bit of a "strange loop" going on, because Paul used Reflector to learn how Expression works on the inside...and many of the classes and concepts he's looking at were designed by the same guy who wrote Reflector.

 

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 26 Aug 2008 20:48

My one lifelong hobby is reading.  My house is full of bookcases and my floors are covered with books that don't fit.  I read a lot of non-fiction:  history, science, philosophy.   I always tell people I haven't read sci-fi since my early 20s, which really means I only read 2 or 3 sci-fi novels a month.  Typical geek reading really.  One of my biggest challenges with travelling is choosing what books to take.  I like to travel light, and I've gone on trips where half the weight of my luggage was books...and of course, none of them taste good on the trip so I have to buy other ones. 

In February, I bought a Kindle to take on the airplane, but (much to my surprise) started reading it on the bus and now prefer Kindle books for reading in bed.  The weight is perfect.  I've loaded my Kindle with classic "Big" books that I can dip into when I want to.  For example, Russell's "History of Western Philosophy" at 700 pages; all 3 volumes of Stephenson's "System of the World" trilogy, each about 600 pages; "War and Peace"; the Pepys diary.  These are much easier to read on the Kindle.

 The battery life is excellent:  1 week if I am reading heavily (vacation), 2-3 weeks when I'm only reading an hour or two a day.  Early complaints about battery life seem to have been from people who didn't understand they should turn the wireless off (it's lousy for reading the internet and blogs...Amazon may have been better off not including those features and focusing on books).

Book selection is still an issue...however there were about 90,000 books when I bought the device and there are 165,000 today.  On a monthly basis books come out I was looking for earlier.  However we still need 10x more books.  For example, looking under English history Amazon lists 794 Kindle books versus 98,000 book-books (many out of print and obscure of course). 

 The device is no beauty.  I think a lot of folks are turned off...expecting Apple-grade industrial design.  Fine...another Amazon mistake, but if you are a reader, you won't notice the looks after the first 100 pages.  The Next and Last page buttons are too easy to hit.  The page transitions are slow...this is a fundamental problem with eInk that is going to take time to fix.  The pages are slightly too small...you have to switch pages a lot.  Forget pictures, let alone color.  The Kindle is for reading books--big books like the ones I have on it, not for looking at pictures.  All in all, the device needs to be improved, but the weight and the clarity of the text make up for these other deficits.  

 The real key is the Service.  Amazon absolutely nailed this in Version 1.  You order a Kindle from Amazon's site and it comes pre-configured for your account.  You have to plug it in to start charging the battery, but you can use it while it charges.  I use my laptop and the web to buy books...Amazon's site is far easier to navigate from a laptop than from the Kindle itself.  You find a book, you One-Click it, and within a few minutes you can start reading it.  I've bought books on impulse right before running for the bus.  There is no wireless configuration, no settings you need to input, no passwords or authentication.  It just works. 

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Saturday, 09 Aug 2008 01:30

As I’ve described before, we introduced the new VisualStateManager concept into Silverlight WPF before we added the same functionality in desktop WPF, in violation of our general guideline that Silverlight is functionally a subset of the desktop .NET Frameworks.  We are planning to add full VSM support on the desktop, but we haven’t had time to support all the existing controls and other infrastructure. 

In the meantime, we would like to enable you to start prototyping desktop controls that use VSM and can therefore share templates and implementation with their Silverlight kindred.  So, for prototyping only purposes, you will find attached to this blog entry the full source code for a desktop WPF implementation of VisualStateManager and a behavior system that allows existing WPF controls to work with it. 

The solution contains a VisualStateManager project that implements VisualStateManager, VisualState, VisualStateGroup and the other classes that VSM requires, and a VSMTestApp project that produces a standalone exe that shows VSM templates applied to some Buttons and a custom WeatherControl. 

Another reason for my blogging this project is that it is a powerful example of the Attached Behavior pattern.  It might seem VisualStateManager needs to be added into the core of WPF in order to function, but as the project shows, it can be implemented through use of an attached property and change callbacks.  To see how this works look in VisualStateManager.cs at the VisualStatesGroupProperty and VisualStateGroupsProperty_Changed callback.

Furthermore, the normal pattern for using Silverlight controls with VisualStateManager is to have the controls call GoToState() in their implementation code.  But desktop WPF controls do not have these GoToState() calls.  The solution is to create VisualStateBehaviors that use the Attached Behavior pattern again to inject the GoToState() calls in response to the proper events.  Take a look in the Behaviors folder of the VisualStateManager project to see how this works.  It includes the abilities to write your own VisualStateBehaviors to add VSM support into any control *without* modifying the control itself. 

I plan to use this project to show how Triggers work with VisualStateManager in the future…stay tuned.

This prototype project is compatible with the VisualStateManager from Silverlight Beta 2.  There is no guarantee this version will be compatible with VSM in the Silverlight RTM and there will be an officially support VSM for desktop WPF in the future.  Please don’t use this code for production purposes, it is purely for experimentation and prototyping now. 

Acknowledgements:  Kenny Young, Kurt Jacob, Dave Relyea Karen Corby and Mike Hillberg all contributed to this project.  Kenny in particular deserves credit for writing the original prototype that led to the features implementation in Silverlight.  Karen Corby ported the custom Weather Control from her blog series on VisualStateManager.  Any bugs in the project were introduced by me.

Attached Media: application/x-zip-compressed ( 54 ko)
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 28 Jul 2008 21:37

I was reading a thread about Commands in the WPF Disciples group and noticed a comment about being unable to initialize an attached property where the type was collection.  The problem was unless you put in an explicit Collection object tag, the property is initialized to null when the XAML parser tries to add to it.  I ran into the same issue when working on VisualStateManager.  This markup failed:

<VisualStateManager.VisualStateGroups>

<VisualStateGroup x:Name="CommonStates">

Because the VisualStateGroups property contained a null collection (not an empty collection) and the XAML parser tried to add it.  This markup worked:

<VisualStateManager.VisualStateGroups>

<VisualStateGroupCollection>

<VisualStateGroup x:Name="CommonStates">

But this seemed inconsistent and unnecessary.  The normal way to do this is to initialize the property in the CLR getter, but attached properties were skipping calling the getter.  This is an optimization:  the XAML parser accesses the DP directly rather than use reflection to find and call the CLR property.  Well, the fix is easy:  hide the DP from the XAML parser, which can be done by using a different name for the registered DP (and making it internal is a good idea), and defining the attached property by using the static getter and setter.  So if the DP is called InternalVisualStateGroups and the getter and setter are for VisualStateGroups, the parser will call the static property.

 

Here's a snippet showing how the property is defined that works:

 

        internal static readonly DependencyProperty VisualStateGroupsProperty =

            DependencyProperty.RegisterAttached("InternalVisualStateGroups",

                            typeof(VisualStateGroupCollection),

                            typeof(VisualStateManager),

                            new UIPropertyMetadata(null,

                                    new PropertyChangedCallback(VisualStateManager.VisualStateGroupsProperty_Changed)));

 

        internal static VisualStateGroupCollection GetVisualStateGroupsInternal(DependencyObject obj)

        {

            if (obj == null)

            {

                throw new ArgumentNullException("obj");

            }

            VisualStateGroupCollection groups = obj.GetValue(VisualStateManager.VisualStateGroupsProperty) as VisualStateGroupCollection;

            if (groups == null)

            {

                groups = new VisualStateGroupCollection();

                SetVisualStateGroups(obj, groups);

            }

            return groups;

        }

 

        public static IList GetVisualStateGroups(DependencyObject obj)

        {

            return VisualStateManager.GetVisualStateGroupsInternal(obj);

        }

 

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 22 Jul 2008 20:27
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 11 Jun 2008 01:25

Recently, I talked about how templates in WPF/SL are fundamentally built around the concept of a state machine, where the condition is a Trigger (desktop WPF) or code (Silverlight) and the new state is a group of Setters (desktop WPF) or a Storyboard (Silverlight).  I hinted that in the future we would be making this more formal, and with the announcement of VisualStateManager for Silverlight Beta 2, you can see what I was talking about.

 Christian's introduction thoroughly covers the functionality and tooling, so let me expand on where this is going architecturally:

 VisualStateManager, by providing an abstraction of a VisualState, makes unifying the deskop and web models much more straightforward.  While currently in Silverlight a VisualState contains a Storyboard, in the future it contain a group of Setters, just as in WPF.  And while currently the user must call VisualStateManager.GoToState in code, in the future a GoToState action in the body of a Trigger will allow WPF style "codeless" templates to utiltize VisualStates and get the benefits of automatic transition generation and a more designer-friendly tooling experience.  More soon...

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 28 May 2008 18:15

Julian Dominguez is writing a series about the PresentationModel pattern and using it with WPF.  http://staff.southworks.net/blogs/jdominguez/archive/2008/05/20/First-approach-to-Presentation-Model-with-DataTemplates.aspx and Glenn Block has just posted a little on the same topic:  http://blogs.msdn.com/gblock/archive/2008/05/24/using-viewmodels-and-datatemplates-to-compose-your-ui.aspx.

These two have been thinking a lot about application composition as part of the PRISM project.  WPF is still so new that we still don't know all the best practices and techniques...this sort of exploration and dialogue is essential to clarification and communication within the community of WPF developers, and I like what I've read so far.

 On naming, my opinion at this point is the the Model-View-ViewModel pattern is a WPF-specific version of the PresentationModel pattern.  PresentationModel is a lot easier to say and to write, and is more widely known...but for now I'm sticking to M-V-VM terminology in my own thinking in order to capture the WPF-ness and to avoid any interpretation conflicts.  I used to be a mathematician. It is very common for the author of each new paper or book on mathematics to use a slightly different definition for even basic terms like Set or Point or Line.  Usually the common terminology is worth the confusion, but sometimes it is nice to come up with a new name to clear the mental palate.

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 27 May 2008 20:37

The Silverlight and desktop WPF implementations of Templates use the same syntax and programming model for describing the tree of objects that make up the control body, but differ in how they describe dynamic changes of the template.  In desktop WPF, this is done using Triggers...for example, a trivial Button Template might look like:

        <ControlTemplate x:Key="MyButton" TargetType="Button">

            <Grid>

                  <Border x:Name="Back" Background="{TemplateBinding Background}">

                        <ContentPresenter/>

                  </Border>

            </Grid>

            <ControlTemplate.Triggers>

                <Trigger Property="IsMouseOver" Value="true">

                    <Setter Property="Background" TargetName="Back" Value="Red"/>

                </Trigger>

            </ControlTemplate.Triggers>

        </ControlTemplate>

As I've explained in previous posts, time and resource constraints left us unable to implement Triggers in the Silverlight 2 timeframe.  We were left then with the problem of delivering the same functionality reusing as much existing code from Silverlight as possible.  The design we came up with evolved from deconstructing Triggers in WPF and thinking about the basic pattern anew.  The fundamental recognition is that a Trigger actually has two parts:  a condition (IsMouseOver == true) and a body (the Setters and other actions in more complex examples). 

The body of the Trigger changes the appearance of the Control...this is what we call a Control State, or a Visual State.  The latter term is more precise, as the Control also has a Logical State which consists of the values of all its properties.  The Condition in a Trigger maps the Logical State (IsMouseOver) to a Visual State (Background = Red). 

In Silverlight we had two existing, fully implemented things we could use to describe Visual States...a collection of Setters like a Style, or a Storyboard.  Since Storyboards allow you to create Visual States that are animated, we choose the second, more flexible construct.  The Condition we left to the Control code itself...and thus we get the Silverlight Beta 1 "Parts and States" model (Parts are an already existing concept from desktop WPF).   Looking forward to unification of the desktop and web Template models, we can imagine a world where a Trigger in the Template contains a GoToState action that triggers the Storyboard instead of the boilerplate code each control must currently write. 

In Silverlight Beta 2, we have taken some steps in that direction, and formalized the concept of a Visual State.  More soon.

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Podcast   New window
Date: Thursday, 22 May 2008 23:05
A few months ago I was interviewed by Craig Shoemaker of Pixel8 about my experiences with Expression and WPF.  The podcast is up now at:  http://pixel8.infragistics.com/shows/gossman
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 21 May 2008 21:41
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 16 May 2008 14:46

The ClickBehavior is about the simplest I can think of.  For illustration purposes I only included one command, but LeftClickCommand, DoubleClickCommand, MouseOverCommand etc. are all obvious extensions:

  public static class ClickBehavior

    {

        public static DependencyProperty RightClickCommandProperty = DependencyProperty.RegisterAttached("RightClick",

                    typeof(ICommand),

                    typeof(ClickBehavior),

                    new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ClickBehavior.RightClickChanged)));

 

        public static void SetRightClick(DependencyObject target, ICommand value)

        {

            target.SetValue(ClickBehavior.RightClickCommandProperty, value);

        }

 

        public static ICommand GetRightClick(DependencyObject target) {

            return (ICommand)target.GetValue(RightClickCommandProperty);

        }

 

 

        private static void RightClickChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)

        {

            UIElement element = target as UIElement;

            if (element != null)

            {

                // If we're putting in a new command and there wasn't one already

                // hook the event

                if ((e.NewValue != null) && (e.OldValue == null))

                {

                    element.MouseRightButtonUp += element_MouseRightButtonUp;

                }

                // If we're clearing the command and it wasn't already null

                // unhook the event

                else if ((e.NewValue == null) && (e.OldValue != null))

                {

                    element.MouseRightButtonUp -= element_MouseRightButtonUp;

                }

            }

        }

 

        static void element_MouseRightButtonUp(object sender, MouseButtonEventArgs e)

        {

            UIElement element = (UIElement)sender;

            ICommand command = (ICommand)element.GetValue(ClickBehavior.RightClickCommandProperty);

            command.Execute(null);

        }

    }

    public class DelegateCommand : ICommand

    {  

        public delegate void SimpleEventHandler();

        private SimpleEventHandler handler;

        private bool isEnabled = true;

 

        public event EventHandler CanExecuteChanged;

 

        public DelegateCommand(SimpleEventHandler handler)

        {

            this.handler = handler;

        }

 

        private void OnCanExecuteChanged()

        {

            if (this.CanExecuteChanged != null)

            {

                this.CanExecuteChanged(this, EventArgs.Empty);

            }

        }

 

        bool ICommand.CanExecute(object arg)

        {

            return this.IsEnabled;

        }

 

        void ICommand.Execute(object arg)

        {

            this.handler();

        }

 

        public bool IsEnabled

        {

            get

            {

                return this.isEnabled;

            }

            set

            {

                this.isEnabled = value;

                this.OnCanExecuteChanged();

            }

        }

    }

    public class ViewModel

    {

        public ICommand Foo

        {

            get

            {

                return new DelegateCommand(this.DoSomeAction);

            }

        }

 

        private void DoSomeAction()

        {

            MessageBox.Show("Command Triggered");

        }

    }

    public partial class Window1 : Window

    {

        public Window1()

        {

            InitializeComponent();

            this.DataContext = new ViewModel();

        }

 

    }

<Window x:Class="WpfApplication1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:WpfApplication1"

    Title="Window1" Height="300" Width="300">

    <Grid>

        <Button Content="Hello" local:ClickBehavior.RightClick="{Binding Foo}"/>

    </Grid>

</Window>

 

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 12 May 2008 21:24

Scott's blog has an extensive list of the new stuff:  http://weblogs.asp.net/scottgu/archive/2008/05/12/visual-studio-2008-and-net-framework-3-5-service-pack-1-beta.aspx

 If you scroll down about half way, you'll find the WPF features:  better startup performance, target performance fixes in the other areas, a new hardware accelerated graphics effects architecture, DirectX interop and a series of data enhancements, most notably better support for writing data virtualizing controls.  This is not your usual collection of bugs fixes...there is a *lot* of new stuff in the release and you'll want to check it out. 

Looking forward to our next few releases, I think you'll see the same sort of priorities:  constant perf improvements, better interop with other UI technologies, and more and better features and controls for data oriented applications.  The core architecture seems to be complete and stable, we just need to flesh out the system and add targeted new features.

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 07 May 2008 17:01

My favorite feature of WPF (desktop and web versions) is attached properties.  It would be good enough if attached properties merely enabled things like keeping layout properties (Canvas.Left) organized by the type of container rather than the type of content, but they also enable a great little design pattern:  Attached Behavior.

Nikhil recently blogged about behaviors in terms of Silverlight (http://www.nikhilk.net/Silverlight-Behaviors.aspx), but of course the same technique is available in desktop WPF and we widely used it during Expression development.  Nikhil describes the technique well, but let me reiterate in Design Patternese:

The Attached Behavior pattern encapsulates "behavior" (usually user interactivity) into a class outside the visual heirarchy and allows it to be applied to a visual element by setting an attached property and hooking various events on the visual element.

One of the first behaviors we wrote in Blend was the ClickBehavior.  The M-V-VM pattern uses Commands instead of events in many cases, but WPF controls don't trigger Commands in all the interesting cases.  Button for example has a Command property, but it only fires when the Button is clicked, not double-clicked or right-clicked.  ClickBehavior defines attached properties like DoubleClickCommand of type Command.  When you set these properties the behavior registers for the MouseRightButtonUp event and in the handler for that event invokes the Command in the DoubleClickCommand behavior.  Interestingly, this same behavior can be used to attach Commands to *any* UIElement, even a rectangle.  This turns out to be useful for adding interactivity to parts of the UI without the extra cost of a full-blown Control. 

You can do a lot with the Attached Behavior pattern.  Drag and drop is an obvious candidate for a behavior.  A single DragDropBehavior class can register for all the basic input events and invoke Commands like OnDrop and OnDrag, allowing you to make any visual a DropTarget or DropSource without sub-classing or adding substantial code to your page.  As I mentioned in my previous post, Silverlight's Parts and States model does not work easily with the built-in desktop WPF controls because those controls do not trigger the state changes.  An attached behavior can hook the right events and do the state transitions...the first prototype of the Silverlight model was written in desktop WPF as an attached behavior. 

More on this pattern later.

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 01 May 2008 17:22

I am an architect of WPF, both the full desktop version and the subset that provides the UI framework for Silverlight.  This subsetting exercise raises challenges I've not run into before when designing software.  Simply put, how do we keep the framework small without completely changing the programming model?  Keeping it small is relatively easy:  just take out classes and APIs.  You of course lose functionality in the process, but almost always when designing software you start out with many features and then must prune back in order to ship.  Subsetting also makes it hard for users to move substantial bodies of code from the big system to the small system.  Not only features, but individual APIs that we decided to cut "because they weren't critical" are naturally called all the time in the application code, and there is no replacement.  Worse, it is easy to get confused reading books about desktop .NET or looking at blog articles about XAML and not be able to tell what is in Silverlight and what isn't.  There was a simple question in the Silverlight forums this morning about how to set the Name of a Framework element.  The user had seen code that simply said fe.Name="foo" and it wasn't working for him.  Well, that code works on desktop WPF and it is highly unlikely the place he saw the example noted that this wasn't available in Silverlight.

To keep somewhat sane, we choose to design around making it possible to port code *from* Silverlight *to* the desktop.  As long as the Silverlight APIs are a subset (with expected differences for application model) of the desktop ones, code should all just compile and run when moved over.  But this is where it gets trickier than we originally imagined.

 With the full desktop frameworks there are usually several ways of doing the same thing.  In Silverlight we eliminate many of these variations in the search for the smallest possible code and surface area.  However, what happens when we eliminate a path that is a best practice for a particular scenario?  For example, there are a number of complex APIs in desktop WPF that are only used if you want the best possible performance...usually with some tradeoff in flexibility.  The System.Windows.Media.Drawing class and its descendents are examples.  These allow you draw shapes into a single visual and render more efficiently.  Not strictly necessary, but they make for much better performance in some scenarios.  These scenarios are still possible in Silverlight, but if you now port your code to desktop, you will be well served to rewrite a big chunk of code. 

The above example is a bit of a special case, and I don't feel bad about it at all.  A much greater struggle that hits a very large number of users is how we do Control templating.  All of the APIs we use in Silverlight's Beta1 control templating model exist in desktop WPF, and yet the templates are completely different.  By subsetting the APIs we ended up changing not just the best practices, but the essential model. 

Let me be clear.  If you write your own custom control in Silverlight, using the Silverlight model, you can create a template for it and take your custom control and its template and run them on desktop WPF.  The problem is, we do not provide Triggers in Silverlight and many of the properties (IsMouseOver, IsPressed) that Triggers depend on to work.  There are technical reasons Triggers were hard to add in Silverlight 2 (though we will add them in the future), but even greater was the test and development cost of adding all the additional properties necessary to make them work.  So, we decided to make the controls have to "trigger" the state changes themselves in code.  All this code works on desktop WPF.  But existing controls, written for the desktop, don't contain the code to "trigger" the state changes, so the control templates don't do anything when applied (they create their children, but don't react to events).

I should add at this point, that we also think there are some advantages for designers and tools of the Silverlight templating model.  The Parts and States model (which is just a pattern using existing APIs) adds structure to a template that makes it easier to understand.  And in the future, when we add Triggers into Silverlight they are completely compatible with the Parts and States model...providing the best of the two models.  Finally, the Beta1 Parts and States model is going to be considerably enhanced in the near future in ways that really show off the advantages and simplify the coding. 

Sorry for the tease about future stuff (watch this space), but this posting is about the essential subsetting problem, and the control templating model has been our greatest struggle in this area.  I hope this helps provide insights into the Silverlight programming model and some of the decisions we've made, which may seem arbitrary and patternless otherwise.

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 08 Feb 2008 06:22
I spent a quite a bit of time late in Blend tracking down memory leaks.  Jossef has written the article I wish I had read then:  http://blogs.msdn.com/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 06 Feb 2008 19:10

There have been a raft of interesting articles and discussions of MVC patterns and WPF.  A practical introduction is here:

http://www.codeproject.com/KB/WPF/MVCtoUnitTestinWPF.aspx

I love the article, but must add I have always struggled with RoutedCommands and CommandBindings.  I think the APIs are too complex for what they do, but more importantly I prefer to route commands through my application model, not through WPF's element tree.  The Blend architecture contains a creature called CommandManager which makes sure commands get to their destination, and we tend to Databind directly to properties of type ICommand (I love ICommand, just not its implementation in RoutedCommand).

Meanwhile, Dr. WPF aptly summarizes the controversy:  http://www.drwpf.com/blog/Home/tabid/36/EntryID/27/Default.aspx

Basically, I have found everyone agrees you should separate your Model and your View, but the details of the rest depend on technology and personal preference. 

Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
New role   New window
Date: Sunday, 06 May 2007 01:44
We recently shipped Expression Blend, the product I had been working on for the last few years.  I love the product and the team, but it was the longest project I've ever worked on, and I was offered a great new opportunity:  to work on WPF, both the desktop version we shipped with Vista and the new Silverlight component.  The work isn't that vastly different.  From many years working with the WPF team, I know most people very well already.  I go to many of the same meetings, just sit on a different side of the room.  But of course there are still those vast areas, little things about the new team, of which I am completely ignorant.  Which is what I wanted:  to learn a lot of new stuff.  Be careful what you ask for, as they say.
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Date: Saturday, 04 Nov 2006 19:08
Kiran just posted the definitive stuff on WPF perf.  Get it here
Author: "JohnGossman"
Comments Send by mail Print  Save  Delicious 
Next page
» You can also retrieve older items : Read
» © All content and copyrights belong to their respective authors.«
» © FeedShow - Online RSS Feeds Reader