Damon Payne: Hand waving software architect

103db signal to noise ratio at < .03% total harmonic distortion
Solution Architect, software developer, geek
Damon Payne at Blogged
2009 Microsoft MVP - Client App Dev
2007 Microsoft MVP - Solution Architecture
 Saturday, January 30, 2010

I haven’t decided where I’m staying yet, but I will be attending MIX 2010 March 15th – 17th.  Are you going to MIX? Drop me a comment!  I will likely be accompanied by someone from BigHammer but I’m always looking for other people to drink beer learn with!  I’ll obviously be leaning heavily towards the Silverlight sessions.  If MIX 2009 is any indication there should be some great content in March. 

Of course, I am hoping to finally see a completely awesome Windows Mobile 7 announcement.  Please?



Saturday, January 30, 2010 2:53:02 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Monday, December 07, 2009

Silverlight 3 ships with out of browser support which is a particularly useful feature.  Combining OOB with the ability to detect network status can allow your users to consume your Web app without a connection.  Combining both of these features with Isolated Storage and the right design approach can provide a seamless Occasionally Connected application experience using Silverlight 3.

Wine Research

I will need another sample application to demonstrate these concepts, this time I’m going with HandWaver Wine Research:

wineresearch0

When we navigate to [Questions] we’re going to see a list of questions about things like Wine/Food pairing and similar topics; the questions were submitted using another system.  The green orb in the upper right hand corner indicates the app is online and connected.  I have also included a button to toggle the online/offline status which is easier than pulling my plug or disabling my network device in Windows.  I will be using the HandWaver.AG Silverlight Guidance project from previous articles.

Application Goals

We only have a couple of functions for this application.  We need to read questions people send us about wine, answer those questions, and send a message to the question asker.  Because some of these questions may take careful thought and I don’t always have an internet connection, I want the application to seamlessly work no matter my connection state.  I have only two modules, abstracted behind interfaces, for accomplishing this: IQuestionRepository and IResearchMessageSender.  I would like to use a dependency-injection like approach for configuring these modules, but I must be able to react to environmental changes as well.

Initializing MEF

MEF is much more than an IoC container and in this article we will explore one of the more intriguing features.  Recomposition in MEF is easy to turn on, not straightforward to get working, and you must design for it.  This should not be taken as a general introduction to MEF but we can review:

MEF works by satisfying [Import]s with matching [Export]s.   Instances with either Imports or Exports are typically called Parts in MEFspeak.  Parts can either be handed to MEF of discovered from some type of Catalog.

Since we have two different parts which need to change in concert, the idea of a Catalog works well here.  I am using a Presenter combined with ViewModel to drive the question/answer screen.  The presenter utilizes MEF to satisfy module needs as follows.

namespace HandWaver.AG.WorkOfflineDemo.PresentationModel
{
    public class ResearchPresenter : IPartImportsSatisfiedNotification
    {
        public ResearchPresenter(IResearchView v)
        {
            _view = v;
        }

        IResearchView _view;        
        IQuestionRepository _qRepo;

        [Import(AllowRecomposition = true)]
        public IQuestionRepository QuestionRepo
        {
            get { return _qRepo; }
            set
            {
                _qRepo = value;
                if (null != _view.ViewModel)
                {
                    _view.ViewModel.QuestionRepo = _qRepo; 
                }
            }
        }

        [Import]
        public NetworkStatusMonitor NetworkStatusMonitor { get; set; }

        public void OnImportsSatisfied()
        {
            NetworkStatusMonitor.GoOnline += new Action(NetworkStatusMonitor_GoOnline);
            NetworkStatusMonitor.GoOffline += new Action(NetworkStatusMonitor_GoOffline);
        }


        public void InitView()
        {
            var mdl = new WineResearchViewModel();
            QuestionRepo.FindUnanswered((qs) =>
            {
                mdl.UnansweredCount = qs.Count;
                mdl.Questions.Clear();
                mdl.Questions = new ObservableCollection<Question>();
                qs.ForEach((q) => mdl.Questions.Add(q));
            });

            mdl.QuestionRepo = QuestionRepo;

            _view.ViewModel = mdl;            
        }

        public void SaveSelected()
        {
            var q = _view.ViewModel.SelectedQuestion;
            QuestionRepo.MarkAnswered(q, () => _view.ViewModel.Questions.Remove(q));
        }

There are two Import definitions for this class.  One is a NetworkStatusMonitor that tells us when connection status changes using the baked-in Silverlight 3 APIs and uses the bare Import attribute.  The second is more interesting as it also sets AllowRecomposition to be true.  What this tells MEF is that we can re satisfy this import later if the situation arises.  This will help us meet our goals if we design carefully: when online, I’ll use a WCF based implementation of IQuestionRepository, when offline I’ll save messages to Isolated Storage to be forwarded on later.  Because I’m setting the current IQuestionRepository as a property of the ViewModel I can actually see this at work:

OnlineQuestionRepo

OfflineQuestionRepo

In each case, note the area highlighted in red and the green/red orb indicating connection status .  How did we accomplish this?

Groups of Services and Re Composition

The high level static structure for the different pieces needed to make this work is pictured here. 

staticstructure

Some extra work is needed to translate this into something MEF can help with.  MEF provides Catalogs, Imports, Exports, and of course the CompositionContainer however the out of the box components did not quite do what I wanted in a straightforward way so some extensions were required.  Let’s walk through the code needed to let ServiceFactory switch between OnlineServices and OfflineServices.

When first starting, we setup the MEF container based on the current connection status:

public class ServiceFactory
 {
     [Import]
     public NetworkStatusMonitor StatusMonitor { get; set; }

     [Import]
     public CompositionContainer Container { get; set; }

     IServiceGroup _services;

     public void Initialize()
     {
         if (StatusMonitor.IsOnline)
         {
             _services = new OnlineServices();
         }
         else
         {
             _services = new OfflineServices();
         }
         AddAll(_services);

AddAll performs the initial composition based on whichever group of services (Modules) were applicable at the time.  Things get interesting when we need to recompose based on an environment change.

void StatusMonitor_GoOnline()
{
    var oldSvc = _services;
    _services = new OnlineServices();
    RecomposeAll(oldSvc, _services);
}

void StatusMonitor_GoOffline()
{
    var oldSvc = _services;
    _services = new OfflineServices();
    RecomposeAll(oldSvc, _services);
}

The intent should be clear at this point.  We are going to remove the “old services” from the Composition and add the “new services” to the composition.  The rest of the code here is a little bit more verbose than need be in order to make it very clear what’s going on.

void RecomposeAll(IServiceGroup old, IServiceGroup @new)
{
    var exportQR = GetDefaultExport(typeof(IQuestionRepository), old.QuestionRepo, false);
    var exportIRM = GetDefaultExport(typeof(IQuestionRepository), old.ResearchMessageSender, false);

    var addQR = GetDefaultExport(typeof(IQuestionRepository), @new.QuestionRepo, true);
    var addIRM = GetDefaultExport(typeof(IResearchMessageSender), @new.ResearchMessageSender, true);

    var batch = new CompositionBatch();
    batch.RemovePart(new SingleExportPart(exportQR, old.QuestionRepo.Name));
    batch.RemovePart(new SingleExportPart(exportIRM, old.ResearchMessageSender.Name));

    batch.AddPart(new SingleExportPart(addQR, @new.QuestionRepo.Name));
    batch.AddPart(new SingleExportPart(addIRM, @new.ResearchMessageSender.Name));
    
    Container.Compose(batch);
}

In each case, we must provide enough information for the CompositionContainer to:

  1. Find the currently exported Part for a given contract
  2. Create a ComposablePart that maps to each
  3. Create new Exports for the new Parts
  4. Create a ComposablePart for the new Exports
  5. Create a CompositionBatch to do the Add/Remove as an atomic operation

I found that the code below was needed in order to successfully accomplish the aim.

protected Export GetDefaultExport(Type contractType, Type implType, bool add)
{
    string contractName = contractType.ToString();
    var metadata = new Dictionary<string, object>();
    metadata.Add("ExportTypeIdentity", contractName);
    Func<object> valueFinder = null;

    if (add)
    {
        valueFinder = () => Activator.CreateInstance(implType);
    }
    else
    {
        valueFinder = () => (from p in Container.Catalog.Parts where p.Metadata["ExportTypeIdentity"] == contractType select p).FirstOrDefault();
    }
    var export = new Export(contractName, metadata, valueFinder);
    return export;
}

/// <summary>
/// A simple container to work with MEF container constructs
/// </summary>
public class SingleExportPart : ComposablePart
{
    public SingleExportPart(Export e, string implVal)
    {
        _export = e;
        _implVal = implVal;
    }

    Export _export;
    string _implVal;

    public override IEnumerable<ExportDefinition> ExportDefinitions
    {
        get { return new ExportDefinition[] { _export.Definition }; }
    }

    public override IEnumerable<ImportDefinition> ImportDefinitions
    {
        get { return Enumerable.Empty<ImportDefinition>(); }
    }

    public override object GetExportedValue(ExportDefinition definition)
    {
        return _export.Value;
    }

    public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
    {
        
    }
    public override IDictionary<string, object> Metadata
    {
        get
        {
            return new Dictionary<string, object>();
        }
    }

    public override bool Equals(object obj)
    {
        return GetHashCode().Equals(obj.GetHashCode());
    }

    public override int GetHashCode()
    {                
        return ("SingleExportPart" + _implVal).GetHashCode();
    }

}

Without the source for the MEF Preview I would have had a more difficult time with this.  It seems like it should be easier to remove Parts from the composition.  To be fair, this is easier if you are using [ImportMany] instead of [Import].  The final part needed to tie everything together is to add a PartCreationPolicy to the Parts being added & removed from the composition batch:

[Export(typeof(IQuestionRepository))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class QuestionRepository :   IQuestionRepository
{

Without specifying the NonShared CreationPolicy MEF will by default create a single instance of the Part.  When trying to remove the part from the CompositionContainer MEF will throw an exception basically stating that the Part couldn’t be removed because it was still being used elsewhere to satisfy another Import.

Further Research

The example shown here is somewhat incomplete.  Because service calls in SilverLight are always asynchronous, we would probably want some thread safety as we swap Imports in and out.  It would also be appropriate to enhance the interfaces used here to notify Parts as they are being added/removed such that the Offline/Online families of services can do appropriate cleanup.



Monday, December 07, 2009 8:22:31 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, November 25, 2009

Before PDC 2009, I had a short wish list for the next version of Silverlight:

  1. Real support for commanding
  2. Some kind of full trust mode similar to Click Once
  3. More complete data binding
  4. Context Menus
  5. Relational (Isolated) Storage

I was pretty excited as The Gu’s keynote played out and I saw my wish list filled one item at a time.  There are some other things I’d like, but these are things that aren’t in WPF either so I don’t really dare hope for them.  These items include things like adding extensibility to the Binding framework: too many aspects are internal/sealed black boxen.

The missing #5 would probably have involved something like a cross platform SQL Compact.  The ability to drop a small relational store into Isoloated Storage (or anywhere on the file system using elevated trust) would open up a whole new avenue for Silverlight applications.  Even without tools like the Entity Framework this could be huge.

I recalled my Return of the Smart Client article where I expressed what I believe are common concerns and frustrations developers have when building Enterprise applications using the usual web development tools.  If you needed further convincing that Silverlight is a real alternative for creating browser delivered rich internet applications you need only review day two of the PDC 2009 keynote.  Silverlight is as big as anything going on at Microsoft.  I can’t wait for MIX 2010!



Wednesday, November 25, 2009 2:36:02 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 05, 2009

In just over a week, on November 14th, I will be speaking at the Chippewa Valley Code Camp taking place way up in Menomonie, WI on the UW-Stout campus.  The topic is Advanced Silverlight Development however the content will be somewhat different than my talk by the same name I gave at MadCamp a little while ago.  Doug and company run a healthy community so I’m looking forward to good conversations.

Details on the code camp can be found at: http://www.chippewavalleycodecamp.com/ 

The schedule of topics can be found here: http://www.chippewavalleycodecamp.com/Schedule/2009Schedule/tabid/74/Default.aspx

The elusive Christopher J. Barwick will be accompanying me and making his return to Public Nerd Life.  I am looking forward to seeing Jason Bock and Chris speak, and I’ll probably check out some of the non-Microsoft or Building Better Software topics in between.  We’ll be up the night before and open to grabbing a drink with any local geeks or speakers who may be available.



Thursday, November 05, 2009 10:18:41 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, October 21, 2009

This may be obvious to some, but by calling out to JavaScript within the document hosting your Silverlight application, you can do some powerful things.  Back in the day, we used to sometimes use an href with “mailto” as a poor man’s contact form – hosting solutions with databases and backups weren’t always as cheap and plentiful as they are today.  If you lack a Service Layer to email solution in your environment, you can always try the following:

private void Mailto_Click(object sender, RoutedEventArgs e)
{
    var svc = new Modules.BrowserHostService();
    svc.CallHostFunction("MailTo", "damon@damonpayne.com", "Damon", "Try this Wine!", 
        "Roger Sabon Chateauneuf du Pape 2005", "11F16974-8EE1-4c0c-8AB4-21EF0B7BF087");
}

Where BrowserHostService is part of a demo that I’m working on.  The implementation is very simple:

public class BrowserHostService : IHostService
{
    public void CallHostFunction(string func, params string[] args)
    {
        HtmlPage.Window.CreateInstance(func, args);
    }

This method does everything needed to invoke a JavaScript method on the document containing the Silverlight application.  For invoking the user’s default mail program, you could write a function like what’s shown below.  The only item of note is that the parameter orders must match up.  If you’ve done much Reflection coding you should be used to this.

<script type="text/javascript">
    function MailTo(toEmail, fromUser, subject, suggestTopic, suggestCode) {

        var body = fromUser
        + ' thought you would really enjoy '
        + suggestTopic 
        + ' and there is some info about that on TastingProject.com.   '
        + 'Why not head over to http://localhost:5785/TastingProject.UITestPage.aspx?code='
        + suggestCode 
        + ' and check it out?';

        window.open('mailto:'+ toEmail +'?subject=' + subject+'&body='+body);
    }        
</script>

The preceding C# and JavaScript produces the following result on my machine in Outlook:

AGmailto

Of course you would have to rely on your end user to hit the Send button but this may be a quick and dirty way to get email functionality if you don’t have complete control over your environment.



Wednesday, October 21, 2009 10:24:18 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, October 14, 2009

On Saturday, October 24th I will be speaking at the Madison .NET User’s Group’s annual Code Camp: MadCamp.  You can find general information about MadCamp here. My presentation will be on Advanced Silverlight Topics.  They are going to be giving away a lot of cool stuff, particularly around Windows 7.  The group has combined the code camp event with a Microsoft sponsored Windows 7 launch party so it should be pretty sweet.  I will be tweeting on the subject using #madcamp09 and I hope to see you there



Wednesday, October 14, 2009 7:36:51 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, October 04, 2009

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

What’s in a name?

If you have worked in the Windows Forms designer, ASP.Net ViewState, ASP.Net Control Templates, or ever used a design surface of any kind you are likely familiar with the concepts of a Naming Container and Name Providers.  The first Label I drag onto a form might get a name of “Label0”, then “Label1” and so on.  Many visual technologies will throw an exception if two items inside the same container have the same name.  We will need this idea for AGT very soon, so now is the time to implement it.

Design Goals

The design goals for this next step are fairly simple:

  1. We must have a notion of A Container.  This container has children, this container will use some sort of Name provider to provide a default name for each new Child added to it.
  2. The Type of the children should be inspect able, such that we can supply names like “Foo0”, etc.
  3. We do not need to support a parent-child relationship between Containers (like asp.net does).
  4. We should let the Caller set the name on its child

The only remaining decisions are small but important. 

  1. Is there any value to having an INamingContainer interface or can we use an existing mechanism to expose children?
  2. Is there any value to having an INameable interface for items to be named?

I’m going with “yes”, and “no”, respectively.

INamingContainer

I’m going to create a simple INamingContainer interface which can be implemented by containers (like a design surface) that want their users to have a unique name.  I could make this part of the IDesigner interface but I’d like this to be optional.  I am still in my IDesignableControl-centric world though.

namespace DamonPayne.AGT.Design
{
    /// <summary>
    /// Represents something that has children needing unique names
    /// </summary>
    public interface INamingContainer
    {
        IList<IDesignableControl> Children{get;}
    }
}

This is all we need, we can now enumerate the children and generate a unique name.

INameProvider

The interface for INameProvider is equally simple.

namespace DamonPayne.AGT.Design.Contracts
{
    public interface INameProvider
    {
        string GetUniqueName(INamingContainer container, IDesignableControl newChild);
    }
}

As I mentioned before, I’d like to follow the familiar convention of ControlType[number], so I’m ready to build a default implementation for INameProvider.  This is pretty easy using LINQ.

namespace DamonPayne.AGT.Design.Services
{
    /// <summary>
    /// A name provider that uses the last part of type name plus 
    /// </summary>
    public class TypeScopedNameProvider : INameProvider
    {
        public string GetUniqueName(INamingContainer container, IDesignableControl newChild)
        {
            var type = newChild.GetType();
            string namePart = type.Name;
            int existingCount = (from c in container.Children where c.GetType() == type select c).Count();
            return namePart + existingCount;
        }
    }
}

 

Hooking up DesignSurface

In order to finish up, I only need to hook my implementation up using Unity and call the name provider whenever a new item is added to the DesignSurface.

[Dependency]
public INameProvider NameProvider { get; set; }

 

private void EnsureName(IDesignableControl dc)
{
    if (string.IsNullOrEmpty(dc.DesignTimeName)) 
    {
        string name = NameProvider.GetUniqueName(this, ((DesignSite)dc).HostedContent);
        dc.DesignTimeName = name;
    }  
}

I can drag things out without a name now, and everything looks the way it should with the generated naming.  My glorious purple couches and poorly drawn speakers have names!  Now that I’ve been learning Expression Design I should really take another crack at drawing those speakers.

21ss0

I’ve really got to fix the way that PropertyGrid looks too.

Conclusion

The Service/Module based approach continues to prove itself out as the correct approach for making it easy to add new functionality to the system.  Adding a name provider was a small feature, but the next step won’t be so easy.

You can get the source code from codeplex.  This article represents change set 28479.

The live demo has been updated and can be viewed here.



Sunday, October 04, 2009 8:08:07 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 24, 2009

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Atrophy

As of AGT[19] I was getting ready to extend Commanding and introduce some other concepts in order to get Undo/Redo support.  Of course, that was many months ago and I’ve let this sit for a while haven’t I?  Since that time a lot has happened.  Silverlight 3 has shipped, there are many more class libraries available, and Silverlight in general is being taken more seriously.  It’s time to continue working on the design surface project.

Ok, fine, I also need AGT for some other projects.  I need to take some time to bring the project up to the state of the art and change direction slightly to move the road map around to be more in line with my own short term needs.  Let’s get started.

If you’re new to this project, you can also check out the Codeplex site.

Silverlight 3 Upgrade

Since I’ve been through a machine repave or two since my last work I had to get Team System set back up for Codeplex.  I didn’t realize this until after I’d opened the solution and done the conversion wizard so I was concerned.  Sure enough, the project upgrade hozed the source control bindings but I was able to get it fixed using the Change Source Control command.  With this done I built and ran with no problems, however trying to change anything revealed that source control was most likely irrevocably ruined so I got latest and went back to work.

Once I got through all this, the Silverlight 3 upgrade went off without a hitch.  I found exactly zero breaking changes in the application so far; this is much nicer than some of the previous Silverlight 2 cycles I had gone through.

While no changes were strictly necessary, I had to think about taking advantage of new Silverlight 3 features.  I quickly cycled through my mental list of new Silverlight 3 features.  I may use things like Behaviors in the future.  One thing I wasn’t thrilled with from Silverlight 2 was the copy/scale/glass approach I had to take for creating my drag & drop “thumbnails” of controls.  I sat down to see how much work it would take to create an IDragTypeCreator implementation using WritableBitmap.  WriteableBitmap still has some bizarre behavior in some situations so unfortunately I had to stick with the old implementation.

Refactoring

Pretty much any time I look at old code, I’m eager to apply whatever I’ve since learned to it.  AGT is no exception.  In order to get my head back into this codebase I needed to come up with a refactoring goal that would cause me to review everything…

Moving to Unity

Now that Unity for Silverlight is in good shape, there’s no reason for me not to use it.  I have now taken a dependency on Unity 1.2.  It was hard to say goodbye to my own IoC container but it needed to be done.  Were there any issues in this upgrade?  Oh, you might say so…

  1. I removed my IService interface and replaced with Unity [Dependency] attributes.  This of course involved touching nearly every file in the project.  Find an IService interface, find the implementing classes and the importing classes; lather, rinse repeat.  This was super-painful.

  2. I decided to keep my own EventAggregator for now.

  3. I am also keeping my lame Region Manager for now

  4. The old Creative Commons declarations were removed since AGT is really MS-PL now.

While this resulted in a massive change set, it felt good.  This was a very eye-opening experience:

Changing your IoC container might mean touching most of the files in your solution!

Design Surface

Once I got the solution back up and running with Unity and Silverlight 3, I started looking at areas where I could clean up the design.  The DesignSurface implementation is only 300 lines right now, but is also likely to grow in the future.  I decided to use a concept from another article to encapsulate drawing on the design surface.

namespace DamonPayne.AGT.Design.Behaviors.Drawing
{
    public abstract class DrawingBehavior
    {
        public DrawingBehavior(Canvas surface)
        {
            Surface = surface;
        }

        /// <summary>
        /// The surface we're drawing on
        /// </summary>
        public Canvas Surface { get; private set; }

        /// <summary>
        /// Mouse click point relative to Surface    
        /// </summary>    
        public Point StartPoint { get; set; }

        public abstract void StartDrawing(Point s);

        /// <summary>    
        /// Give derrived classes a chance to determine if they can or should return a valid     
        /// Shape in their current state    
        /// </summary>    
        /// <param name="g"></param>    
        /// <returns></returns>    
        public virtual bool ShouldStopDrawing(DrawingGestures g)
        {
            return (g == DrawingGestures.MouseLeftButtonUp);
        }

        /// <summary>    
        /// Stop drawing and return the final Shape    
        /// </summary>    
        /// <returns></returns> 
        public abstract Shape StopDrawing();


        /// <summary>    
        /// Pass Mouse events through to the DrawingBehavior    
        /// </summary>    
        /// <param name="e"></param>    
        public abstract void MouseMove(MouseEventArgs e);
    }

}

If you are a long-time follower of this series or you’ve read the road map on Codeplex, you’ll know that I intend to have an extensible behavior mechanism for making things happen on the design surface.  DrawingBehvior is the first step in that direction, and also allows me to take a lot of code out of the design surface and move it to a dedicated construct.

namespace DamonPayne.AGT.Design.Behaviors.Drawing
{
    public class RectangleDrawingBehavior : DrawingBehavior
    {
        public static readonly double SELECT_RECT_STROKE_WIDTH = 3.0;
        public static readonly double SELECT_RECT_RADIUS_X = 0.0;
        public static readonly double SELECT_RECT_RADIUS_Y = 0.0;

        public RectangleDrawingBehavior(Canvas surface) : base(surface) { }

        public Rectangle DrawingRect { get; set; }

        public override Shape StartDrawing(Point s)
        {
            StartPoint = s; 
            DrawingRect = new Rectangle { Width = 5.0, Height = 5.0, };
            ApplyShapeStyle(DrawingRect);
            DrawingRect.SetValue(Canvas.LeftProperty, s.X);
            DrawingRect.SetValue(Canvas.TopProperty, s.Y);
            Surface.Children.Add(DrawingRect);
            return DrawingRect;
        }

        public override Shape StopDrawing()
        {
            var rVal = DrawingRect;
            DrawingRect = null;
            return rVal;
        }

        public override void MouseMove(MouseEventArgs e)
        {
            Point localMousePos = e.GetPosition(Surface);
            if (StartPoint.X < localMousePos.X)
            {
                double width = localMousePos.X - StartPoint.X;
                double height = localMousePos.Y - StartPoint.Y;
                if (width > 0 && height > 0)
                {
                    DrawingRect.Width = width;
                    DrawingRect.Height = height;
                }
            }        
            else // northwest drag        
            {            
                double width = StartPoint.X - localMousePos.X;
                double height = StartPoint.Y - localMousePos.Y;
                if (width > 0 && height > 0)//need this safety here in case a resize rectangle "crosses" itself.           
                {
                    DrawingRect.Width = width;
                    DrawingRect.Height = height;
                    DrawingRect.SetValue(Canvas.LeftProperty, localMousePos.X);
                    DrawingRect.SetValue(Canvas.TopProperty, localMousePos.Y);   
                }       
            }         
        }

        public virtual void ApplyShapeStyle(Shape s)
        {
            DrawingRect.StrokeThickness = SELECT_RECT_STROKE_WIDTH;
            DrawingRect.RadiusX = SELECT_RECT_RADIUS_X;
            DrawingRect.RadiusY = SELECT_RECT_RADIUS_Y;
            DrawingRect.Stroke = new SolidColorBrush(Color.FromArgb(0xFF, 0x15, 0x05, 0xFF));
            DrawingRect.Fill = new SolidColorBrush(Color.FromArgb(0xFF, 0x49, 0x59, 0xFF));
            DrawingRect.Opacity = .50;
            DrawingRect.SetValue(Canvas.ZIndexProperty, 1000);
        }

    }
}

Now the design surface code is a bit smaller.  The design surface is still assuming the selecting shape is a rectangle but I can fix that in the future.  I will probably also make the selection strategy pluggable at some point. 

Conclusion

Since there are no functional changes I have not updated the live demo.  You can get the most recent code from codeplex.  The final change set as of the end of this article is 28467.  The next AGT few articles will bring more interesting features, and yes I will get back to the Undo framework eventually.



Thursday, September 24, 2009 8:00:22 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, September 21, 2009

In my last article on View-based navigation, I mentioned that a useful Navigation History module could be built to work in concert.  This article discusses the design and implementation of that module. In this case my design goals are more straightforward:

  1. Allow the size of the navigation history to be set so as to control memory usage
  2. Allow going forwards and backwards in the history
  3. Allow inspection of the navigation history
  4. Allow aspects of navigation history to be bindable

Navigation History

As with the core navigation concepts I went over previously, there is some basic Navigation History built into the Frame class in Silverlight 3.  Since I’ve extended the core navigation concepts I can also add additional hooks for navigation.  As usual, I will first think of my design goals and craft an interface.

public interface INavigationHistory : INotifyPropertyChanged
{
    /// <summary>
    /// How many Views do we want to keep around?
    /// </summary>
    int HistorySize { get; set; }

    /// <summary>
    /// Go back one View, return the next active view
    /// </summary>
    IView GoBack();


    /// <summary>
    /// Go forward one view, return the next active view
    /// </summary>
    /// <returns></returns>
    IView GoForward();

    /// <summary>
    /// Can we go back based on current position?
    /// </summary>
    bool CanGoBack{get;}

    /// <summary>
    /// Can we go forward based on current position
    /// </summary>
    bool CanGoForward{get;}

    /// <summary>
    /// Called by clients to add a view to history
    /// </summary>
    /// <param name="v"></param>
    void Navigated(IView v);

    event Action<IView> NavigatedToView;

    event Action<IView> HistoryItemRemoved;

    /// <summary>
    /// Get the items in the current history, allow a jump to a specific point
    /// </summary>
    ObservableCollection<IView> CurrentHistory { get; }
    

    /// <summary>
    /// Go to a specific View in the history
    /// </summary>
    /// <param name="historyIndex"></param>
    void GoTo(IView v);

    /// <summary>
    /// Removes the most recent item
    /// </summary>
    /// <returns></returns>
    IView Pop();
}

Including INotifyPropertyChanged here means aspects of the navigation history will be bindable: CanGoBack, CanGoForward, and CurrentHistory.  The other parts of the interface should be self explanatory.

Binding to History

Using the previous Audi Fans demo, I can now make the navigation buttons in the lower right hand corner work.

navhist0

The XAML for creating these buttons is fairly simple, note the {Binding} aspects:

<StackPanel Orientation="Horizontal" Grid.Row="2" Margin="5" HorizontalAlignment="Right">
    <TextBlock Style="{StaticResource TextStyle}" >Navigation: </TextBlock>
    <Button x:Name="GoBack" IsEnabled="{Binding Path=History.CanGoBack}" Click="GoBack_Click">
        <Button.Content>
            <TextBlock Style="{StaticResource TextStyle}" Foreground="Black">&lt; Back</TextBlock>
        </Button.Content>
    </Button>                    
    <ComboBox x:Name="JumpCmb" DataContext="{Binding}" ItemsSource="{Binding Path=HistoryItems}" SelectedItem="{Binding Path=CurrentViewName, Mode=TwoWay}" Margin="10,0,10,0" Width="250" >                        
    </ComboBox>                     
    <Button x:Name="GoForward" IsEnabled="{Binding Path=History.CanGoForward}" Click="GoForward_Click">
        <Button.Content>
            <TextBlock Style="{StaticResource TextStyle}" Foreground="Black">Forward &gt;</TextBlock>
        </Button.Content>
    </Button>
</StackPanel>

In order to satisfy these bindings, the Navigation History implementation has been added to the MainViewModel for the front page.  You will note that I’m not binding directly to the History.CurrentHistory but that some additional fields have been added to MainViewModel:

ObservableCollection<string> _histItems;

/// <summary>
/// Silverlight crashes if you use a Page (IView) as a binding source.  Lame.
/// </summary>
public ObservableCollection<string> HistoryItems
{
    get
    {
        return _histItems;   
    }        
}


string _currentViewName;

public string CurrentViewName
{
    get { return _currentViewName; }
    set
    {                
        if (value != _currentViewName)
        {
            _currentViewName = value;
            OnPropertyChanged("CurrentViewName");

            if (_viewMap.ContainsKey(value))
            {   
                Navigation.GoTo(_viewMap[value]);
            }
        }
    }
}

Pit of failure: Silverlight does not seem to like having a Page object as a binding source except when doing Element binding.  This may be a low level implementation detail that’s just not supported, or it may be because the Pages in question are not visible and this causes some fundamental failure.

So there is a layer that maps IView names back to the INavigationHistory because Silverlight binding doesn’t like binding to a visual element that is not currently visible.

Conclusion

That’s pretty much it for Navigation History, be sure to read the previous article if you’d like to see how it fits in with everything else.  There are other directions you could take this, obviously.  If you are using some kind of Region manager you could scope the navigation to each region.  If you are concerned about memory usage, you could create a scheme to use WeakReferences and provide hooks to save just the ViewModel of an IView so that the IView itself could be reconstructed later. 

The updated source code for the HandWaver.AG guidance projects can be found here.



Monday, September 21, 2009 6:17:04 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, September 16, 2009

 

Silverlight 3 ships with a Navigation mechanism.  A control that extends Page can be stored inside the Frame control as content, and Navigation from Page to Page is done by specifying the URI of the target Page.  This mechanism includes navigation history and the ability to go forwards and backwards through said history.  I would, however, like a slightly different programming model around application navigation.

Design goals:

  1. I would like to be able to navigate to a new “screen” from within various places such as Presenters or Commands
  2. I do not want to have to configure each new View I add to the system
  3. I don’t want to have to map Views to URIs to use the Frame
  4. I need to be able to pass parameters to Views as they are navigated to
  5. I need to support having more than one View implementation in the system for a given View interface type
  6. I need an inspect-able navigation history that I can also configure in terms of how much history to keep and so forth
  7. I would like to support animated transitions from View to View, this is Silverlight after all

My sample application will be an “Audi Fan Site” in Silverlight.

Views & ViewModels

I have a Silverlight “guidance” Solution called HandWaver.AG; I will use some concepts from this solution to build the navigation framework and post the entire solution’s source code. 

Pattern: For separation of concerns, I’ll use the Model-View-ViewModel pattern.

I’ll start with a humble IView base interface:

namespace HandWaver.AG.PresenationModel
{
    public interface IView
    {
        string Title { get; }
        void Activate(Action complete);
        void DeActivate(Action complete);
    }
}

Nothing complicated here.  The Activate and Deactivate methods can be called to inform a IView that it is about to be “started” or shut down.  The Action callbacks will facilitate animation later.

Now I need a ViewModel base class that does a little bit of change notification work for me.

namespace HandWaver.AG.PresenationModel
{
    public abstract class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propName)
        {
            if (null != PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
}

I will expand on these concepts in a little bit, for now assume that I will have Controls of some kind that implement IView and bind to ViewModels.

Navigation

For the most simple case, I want to be able to just go to an IVIew.  I’ve created an INavigationService interface.  This is the calling convention that I’ll use.

namespace HandWaver.AG.PresenationModel.Navigation
{
    public interface INavigationService
    {
        /// 
        /// Display the first IView implementation we find
        /// 
        /// 
        void NavigateTo< T >() where T:IView;

At this point I can go ahead and create my sample application and my “Home” screen.  I’m going to re-use the Frame and Page concepts from Silverlight.  I have some navigation buttons that are disabled, a ComboBox that will contain my navigation history, and some HyperlinkButtons up at the top to link to the various IViews I will create.

navapp0

The grey area is my navigation Frame.  What I want to do now is Navigate to the Home screen when the app is loaded.  As you can see from the INavigationService code above, I’m just going to do this:

Navigation.NavigateToIHomeView>();

Adding this now displays my Home screen in the navigation frame…

navapp1

… but how did we get there?  The first item is the discovery of IViews.

Discovering Views

In order to meet my design goals, I need to figure out how to find IView implementations automatically without having to create some kind of View Registry.  In my implementation of the INavigationService interface, reflection is the key.  It’s worth going over this code as everything else depends on it:

private void MapViewTypes()
{
    _viewMap = new Dictionary<Type, List<Type>>();
    //Note: we're making a giant assumption here that all Views are in this assembly.  MEF could help?
    
    var types = _viewAssembly.GetTypes();
    var viewType = typeof(IView);
    var pageType = typeof(Page);

    foreach (var t in types)
    {
        if (t.ImplmentsInterface(viewType) && t.IsSubclassOf(pageType))
        {
            var viewImplType = t;
            //if we have a sub-class of IView, use that instead
            var subViewType = (from v in viewImplType.GetInterfaces() where v.InterfaceExtends(viewType) select v).FirstOrDefault();
            if (null != subViewType)
            {
                EnsureList(subViewType);
                _viewMap[subViewType].Add(t);                        
            }
            else
            {
                continue;
            }

        }
    }
}

ImplementsInterface and InterfaceExtends are extension methods I wrote for System.Type.  When this class is created, I’m reflecting the implementing assembly and finding all classes that implement a descended of IView and storing them in a List.  The implementation for the most basic NavigateTo(), then, just looks like this:

public void NavigateTo() where T : IView
{
    var viewType = _viewMap[typeof(T)][0];
    var view = (IView)Activator.CreateInstance(viewType);

    InitializeView(view);
}

In the most basic case, I am just using the first IView type that I find.  As for how the navigation actually happens, I will have to expose a few more implementation details now.

namespace HandWaver.AG.PresenationModel.Navigation.Modules
{
    [Export(typeof(INavigationService))]
    public class URIFrameNavigationService : INavigationService
    {
        public URIFrameNavigationService(string rootNamespace, Assembly va)
        {
            _viewAssembly = va;
            MapViewTypes();
        }

        static Action nullCallback = () => { };

        [Import(AllowRecomposition=true)]
        public Frame TargetFrame { get; set; }

Note that, for now, I am using MEF as an IoC container.  URIFrameNavigationService uses the Export attribute to tell MEF that it implments the INavigationService contract.  When I construct the instance I pass in some basic information and the class uses MEF to import an instance of the Frame class from Silverlight navigation.  So for the most basic kind of navigation, I’m instantiating a new instance of a Page implementing an IView interface and directly setting the Content of the Frame rather than giving it a URI.

Transitions

Next, I’m going to build the “Models” screen of my Audi fan application; in this case we’re talking about Audi cars and not the usual “Model”.  We can go ahead and look at the implementation for InitializeView() now:

void InitializeView(IView v)
{
    Action go = () => 
    {
        TargetFrame.Content = v;
        v.Activate(URIFrameNavigationService.nullCallback);
        History.Navigated(v);
    };

    if (null != TargetFrame.Content && TargetFrame.Content is IView)
    {
        ((IView)TargetFrame.Content).DeActivate(go);
    }
    else
    {
        go();
    }
}

If the Frame is currently displaying an IView, call it’s deactivate method.  When that method is done, the go action is called which activates the new IView.  We also do something with a History object here which I’ll get to in a little bit.  By using callbacks with Activate and Deactivate we’re able to incorporate animations into the navigation mix.  Here is the Activate implementation for Models.xaml:

public void Activate(Action complete)
{
    var trans = (Storyboard)App.Current.Resources["ExpandIn"];
    trans.Stop();
    Storyboard.SetTarget(trans, LayoutRoot);
    trans.Begin();
    EventHandler sbDone = null;
    sbDone = (o, e) =>
    {
        complete();
        trans.Completed -= sbDone;
    };
    trans.Completed += sbDone;
}

I pull a common animation out of resources and call the giving Action when the animation is complete, being sure to unhook event handlers.  In my case, I’d like to use the same Enter and Exit transitions everywhere in the application and I don’t want to keep copy & pasting this code.  I can move this code to a helper class and invoke it this way everywhere else:

public void Activate(Action complete)
{
    Transition.Animate("ExpandIn", LayoutRoot, complete);
}

public void DeActivate(Action complete)
{
    Transition.Animate("ShrinkOut", LayoutRoot, complete);
}

We could, in future refactoring, create some kind of IViewTransitionManager module that automatically does transitions everywhere, and save the Activate and Deactivate methods for other application specific uses.

You can now run the sample application (link at the end of the article) to see the transitions working from the Home screen to the Models screen.

navapp2

 

Passing Parameters

The View Details Hyperlink buttons, above, should navigate to a special screen showing even more  information about the chosen vehicle model.  When this screen loads, then, the chosen Model will need to be available.  We could set some global User State variable specifying what model of Audi was chosen but it would be nicer to navigate to the chosen IView and directly pass parameters to it.  What’s more, it would be ideal if this parameter passing could be strongly typed such that we can determine the types of parameters using Intellisense.

We have already seen how the INavigationService implementation locates and instantiates an IView implementation.  Adding another overload the the interface implementation meets all stated design goals.

/// <summary>
/// Navigate to a View, passing parameters to said view using the supplied Action
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="paramSetter"></param>
void NavigateTo<T>(Action<T> paramSetter) where T : IView;

It may not be apparent at first look what this allows us to do, but consider the current example of choosing a vehicle model from a list.  The ViewModel of the screen we are coming from knows what the selected VehicleModel is.  Using the excellent Generics implementation in C# we can navigate to an IView and easily see what parameters we might be able to pass to it via Intellisense.

protected void ViewDetailsClick(object s, RoutedEventArgs e)
{
    VehicleModel mdl = null;
    var lnk = (HyperlinkButton)s;
    mdl = (VehicleModel)lnk.Tag;
    Navigation.NavigateTo< IModelDetailView>((v) => v.TargetModel = mdl);
}

I am cheating a little bit here, at least it feels like cheating.  My list of vehicle models is implemented as a listbox and I am using (abusing?) the Tag property that Controls expose in Silverlight:

<HyperlinkButton Grid.Column="5" Style="{StaticResource MenuLinkStyle}" Content="View Details" VerticalAlignment="Center" Click="ViewDetailsClick" Tag="{Binding}">                                        
</< span>HyperlinkButton>

Since we can use Bindings for Tag, the actual data type for  each VehicleModel is stored with the Hyperlinkbutton and we can pull it in the Click event handler.  The real power of what we are now able to do is demonstrated when we see the intellisense available when navigating to IModelDetailView and exploring the overloads available:

navapp4

navapp3

Since we have a strongly-typed mechanism, we can create a lambda expression that takes the IView instance and we can inspect the list of public properties available on IModelDetailView.  In my opinion this makes for a perfectly discoverable mechanism for passing parameters directly to an IView.  If you need further help, you could create a class something like RequiredViewParameter;  having such a type in the Intellisene dropdown might help clients determine which properties must be set in order for a View to function.  Obviously, we an set as many properties as we want using the lambda expression.

 

Choosing Between Multiple IView Implementations

Often, there may be only one implementation for a given IView interface at run time and compile time.  For example, there may likely be only a RealFooView (the real production visual) and a MockFooView (used only for unit testing related logic) for a given IFooView interface.  In some cases, though, multiple implementations for a given IView interface may be present in the real run-time system.  For example, there may be “basic” and “expert” views of the same data and these views my be different enough that it doesn’t make sense to use DataTemplates and configuration properties to set up the View.  We’ve already seen that we are keeping a list of IView in the INavigationService, we can now add another overload to this interface to elegantly handle situations where more than one IView implementation is available.

You may have noticed in the various screenshots that there is a CheckBox on the UI with accompanying text “I am a Fanboy”.  The goal here is that if users check this item, we will show them a more rich set of data when they choose View Details.  By passing a sort of Predicate to the INavigationService, we can easily accomplish this goal:

navapp5

For now, the Fanboy checkbox sets a global variable we can access from within Models.xaml.cs.  I’ll use this value from within this Navigate code to create a selector function.

protected void ViewDetailsClick(object s, RoutedEventArgs e)
{
    bool isUserFanboy = App.UserIsFanboy;
    VehicleModel mdl = null;
    var lnk = (HyperlinkButton)s;
    mdl = (VehicleModel)lnk.Tag;
    Navigation.NavigateTo<IModelDetailView>((v) => v.TargetModel = mdl,
        (v) => v.IsFanboyView == isUserFanboy);
}

I can now create two implementations of IModelDetailView, a basic page and the “fanboy” page displaying more detailed information.  Based on this CheckBox option, Navigation will send the user to a completely different IView.

Regular View:

navapp6

Fanboy View, with extra data:

 navapp7

In this case, the Fanboy view could probably have been done without an extra view implementation, but you can likely see how this would be extremely useful.

What Explodes?

As more than one friend has pointed out to me, when building classes to fit into a framework mechanism there can often be an Explosion of classes, enums, interfaces, delegates etc.  What explodes under this approach, or under MVVM in general?

For every Screen in your application you could potentially have a new IView interface, a new ViewModel, and possibly a new Presenter or Commands.

Preventing View Explosion

If a particular View does not need extra methods, you can prevent View explosion by using Generics.  Generics are the answer to everything.  If your View needs a ViewModel and nothing else special, use something like this:

public interface IView : IView where T : ViewModel
{
    T ViewModel { get; set; }
}

This allows you to implement Views, gain the navigation benefits, but not create a new IView interface.

namespace HandWaver.AG.NavDemo.Screens
{
    public partial class SampleView : Page, IView<MainViewModel>
    {

 

Preventing ViewModel Explosion

Given the previous example, you may be worried about your ViewModel classes exploding, one per IView interface.  I may have mentioned before that generics are the answer to everything, sometimes lambda expressions are part of the answer but the answer definitely always involves generics.  You might, for example, need a ViewModel that does nothing but encapsulate an already existing Data Type from your domain.  There’s a generic type for that:

/// 
/// If the ViewModel can be satisfied by a pre-existing data type, 
/// just use that
/// 
/// 
public class ViewModel : ViewModel where T : INotifyPropertyChanged 
{
    public ViewModel(T source)
    {
        Payload = source;
    }

    private T _Payload;

    public T Payload
    {
        get { return _Payload; }
        set
        {
            _Payload = value;
            OnPropertyChanged("Payload");
        }
    }
}

Combined with the previous example, you could get away without another IView or ViewModel implementation:

public partial class SampleView : Page, IView< ViewModel<VehicleModel> >

If VehicleModel satisfies all of your needs for a View, you don’t need to create any new classes or interfaces.

I’ll talk about Presenters and Commands in a future article.

Conclusion

While the current trends in MVVM may downplay the role of a View interface, IView can be a powerful part of your programming toolbox.  Since the View is an actor in this pattern, it makes sense to be able to treat Views a certain way.  In this article you’ve seen how you can build a flexible Navigation framework around Views and even support handy features like strongly typed parameter passing and selecting from multiple implementations when present.  You can do all this without manually creating any kind of mapping.

HandWaver.AG: I mentioned elsewhere I would be publishing the source for all of my Silverlight Guidance demos.  You can find it here, though it may be updated by future articles and look slightly differently than what you read here.

You can also run the Demo Application.

Future Tasks

There are a few things I had to leave out as this article was getting too long.  The first is the promised Navigation History module.  This is 99.9% done but must have its own article. 

Second, and not very relevant here, is the Photo Gallery page.  This will serve up a cool demo when I get to it.

Finally, If you read the source code closely you may have noticed my comments about the reflection-based IView discovery mechanism.   The mechanism makes the assumption that all IViews you can navigate to are in the initial startup assembly.  In most applications that might be a safe assumption, but MEF is working on changing that with dynamic XAP loading.  Once I’ve had a chance to cozy up with MEF more I’ll post an updated solution.  Also related to MEF, storing the composition catalog on the App class is probably not a best practice.



Wednesday, September 16, 2009 7:28:20 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Monday, September 07, 2009

It is sometimes useful or necessary to represent complex data types as name/value pairs, or Dictionaries if you like.  While the Data Binding implementation in Silverlight 3 is admirable, there is not a built in way to do this cleanly.  Doing some Internet searches, you may find some approaches like this, from http://silverlight.net/forums/t/51864.aspx :

public class DictionaryItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var dict = value as Dictionary<string, string>;
        if (dict != null)
        {
            return dict[parameter as string];
        }
        throw new NotImplementedException();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Note that in all cases you will find the “ConvertBack” strategy missing.  Since the original source object is not passed to ConvertBack, two-way binding to  name/value pairs is an elusive goal.  The binding mechanisms in Silverlight 3 are not very extensible.  I cannot create my own binding type or provide a new implementation for Property Paths.  The Silverlight 3 Data Binding framework wants real Properties to bind to.  If we must have two way bindings to name/value pairs, we are left with pursuing more extreme measures.

Dynamic Type Generation

I have written in the past about the complete Reflection Emit implementation in Silverlight.  It seemed to me that given a means of representing the names and types of the items we want to pull out of a dictionary as Properties, we could dynamically generate a bindable version of a class represented as a dictionary.  We’ll start with creating a very simple model for Objects with data represented as name/value pairs.

namespace HandWaver.AG.EVModel
{
    public class Attribute
    {
        public Attribute(int id, string name, Type t)
        {
            Id = id;
            Name = name;
            AttributeValueType = t;
        }

        public int Id { get; set; }

        public string Name { get; set; }

        public Type AttributeValueType { get; set; }
    }
}

This attribute, not to be confused with the .NET Attribute, represents a sort of metadata for a single property on an object.  We give it a name (which ultimately must be friendly to becoming a Property name) and a run time type.  A single Attribute might be the "Name” property of some object with a type of string.  We may not ultimately want to bind to every single name/value pair available to us.  A means of representing a certain sub-Model is therefore very helpful.  A List of Attribute will suffice for this demo.

namespace HandWaver.AG.EVModel
{
    public class AttributeViewModel : System.Collections.Generic.List<Attribute>
    {
        public AttributeViewModel() : this( Guid.NewGuid() )
        {

        }

        public AttributeViewModel(Guid g)
        {
            UniqueId = g;
        }

        public Guid UniqueId { get; set; }
    }
}

The AttributeViewModel class exposes a UniqueId property of type Guid, which will be useful later.

Reflection Emit code, while incredibly powerful, can also be tedious, difficult, and error prone.  Once practice that I follow is to have as little dynamic code as possible, calling out to pre built classes and only doing what must be done in dynamically created types.  In order to be friendly to binding and provide a base to extend we’ll use a base class that does most of what we want to do already:

namespace HandWaver.AG.EVModel
{
    public class EntityWithAttributes : INotifyPropertyChanged
    {
        public EntityWithAttributes()
        {
            _values = new Dictionary<string, object>();
        }

        Dictionary<string, object> _values;

        public object this[string key]
        {
            get
            {
                return _values[key];
            }
            set
            {
                _values[key] = value;
                OnPropertyChanged(key);
            }
        }


        protected void OnPropertyChanged(string propName)
        {
            if (null != PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

Next, we’ll build a class to create the dynamic types.  I’m currently calling this a Bindable Entity-Value Builder.  It’s worth going over the Reflection Emit code in some detail.  The public interface for BindableEVBuilder is a single method:

public static Type GetDecoratorType(AttributeViewModel prototype)
{
    EnsureDynamicAssembly();
    EnsureModelTypes();
    if (!_modelTypes.ContainsKey(prototype.UniqueId))
    {
        BuildDecoratorType(prototype);
    }

    return _modelTypes[prototype.UniqueId];        
}

We can look at the first several methods later.  The bulk of our work is done in BuildDecoratorType.

static void BuildDecoratorType(AttributeViewModel prototype)
{
    var typeBuilder = _moduleBuilder.DefineType("HandWaver.AG.EVModel.TypeDecorator.DictWrapper"+ GetName(prototype.UniqueId),
        TypeAttributes.Public | TypeAttributes.Serializable | TypeAttributes.Class, 
        typeof(EntityWithAttributes));

    foreach (var attribute in prototype)
    {
        BuildProperty(typeBuilder, attribute);
    }
    _modelTypes.Add(prototype.UniqueId, typeBuilder.CreateType());
}

So far there’s nothing clever here, just creating a dynamic class that extends EntityWithAttributes and making sure that we only generate one dynamic type for each AttributeViewModel by coming up with a naming scheme.  Properties are somewhat special in the .NET CLR.  In order to create a property using IL, the property itself must be defined as well as a getter and setter method.

static void BuildProperty(TypeBuilder typeBuilder, Attribute attr)
{
    var baseType = typeof(EntityWithAttributes);
    var propertyBuilder =
        typeBuilder.DefineProperty(attr.Name, PropertyAttributes.None, attr.AttributeValueType, null);
    // The property set and property get methods require a special
    // set of attributes.
    MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;

    var getterBuilder = BuildGetter(typeBuilder, attr, baseType, getSetAttr);

    var setterBuilder = BuildSetter(typeBuilder, attr, baseType, getSetAttr);

    propertyBuilder.SetGetMethod(getterBuilder);
    propertyBuilder.SetSetMethod(setterBuilder);
}

The getter is more interesting than the setter in this situation.

private static MethodBuilder BuildGetter(TypeBuilder typeBuilder, Attribute attr, Type baseType, MethodAttributes getSetAttr)
{
    var getterBuilder = typeBuilder.DefineMethod("get_" + attr.Name, getSetAttr, attr.AttributeValueType, Type.EmptyTypes);
    var getterILGen = getterBuilder.GetILGenerator();

    var baseGetterInfo = baseType.GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
        null, new Type[] { typeof(string) }, null);

    LocalBuilder localValBuilder = getterILGen.DeclareLocal(attr.AttributeValueType);
    // Preparing labels
    Label label20 = getterILGen.DefineLabel();
    // Writing body
    getterILGen.Emit(OpCodes.Nop);
    getterILGen.Emit(OpCodes.Ldarg_0);
    getterILGen.Emit(OpCodes.Ldstr, attr.Name);
    getterILGen.Emit(OpCodes.Call, baseGetterInfo);
    if (attr.AttributeValueType.IsValueType)
    {
        getterILGen.Emit(OpCodes.Unbox_Any, attr.AttributeValueType);
    }
    else
    {
        getterILGen.Emit(OpCodes.Castclass, attr.AttributeValueType);
    }
    getterILGen.Emit(OpCodes.Stloc_0);
    getterILGen.Emit(OpCodes.Br_S, label20);
    getterILGen.MarkLabel(label20);
    getterILGen.Emit(OpCodes.Ldloc_0);
    getterILGen.Emit(OpCodes.Ret);
    return getterBuilder;
}

It is a convention that property methods are named as get_ and set_ plus the actual public property name.  What’s interesting here is the code we must generate to call the dictionary methods on the base class.  You will note that the method name is “get_Item”, which I only discovered by using Reflector.  I made the decision that I wanted I wanted the generated Properties to be strongly typed rather than return Object.  After emitting the OpCodes for calling the base class’s dictionary get method, we cast the Object to the type specified by the Attribute used to build this Property.  When I was first testing this I had properties of type string and double; the string was working and the double was not.  The Castclass opcode produces odd results when working with value types, so I found the correct Opcode for non-reference types which is naturally OpCodes.Unbox.

If you want to become more familiar with what the CLR is really doing, try writing Reflection Emit versions of some common tasks.

The setter code is straightforward as far as these things go.

private static MethodBuilder BuildSetter(TypeBuilder typeBuilder, Attribute attr, Type baseType, MethodAttributes getSetAttr)
{
    var setterBuilder = typeBuilder.DefineMethod("set_" + attr.Name, getSetAttr, null, new Type[] { attr.AttributeValueType });
    var setterILGen = setterBuilder.GetILGenerator();
    var baseSetterInfo = baseType.GetMethod("set_Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(string), typeof(object) }, null);
    setterBuilder.SetReturnType(typeof(void));
    setterBuilder.SetParameters(attr.AttributeValueType);
    // Parameter name=value
    ParameterBuilder value = setterBuilder.DefineParameter(1, ParameterAttributes.None, "value");
    ILGenerator gen = setterBuilder.GetILGenerator();
    // Writing body
    gen.Emit(OpCodes.Nop);
    gen.Emit(OpCodes.Ldarg_0);
    gen.Emit(OpCodes.Ldstr, attr.Name);
    gen.Emit(OpCodes.Ldarg_1);
    gen.Emit(OpCodes.Call, baseSetterInfo);
    gen.Emit(OpCodes.Nop);
    gen.Emit(OpCodes.Ret);
    return setterBuilder;
}

 

Proving it Out

With a first draft of the reflection code written, I wanted to write a simple UI to smoke test three obvious Data Binding scenarios:

  1. Basic binding to a dynamically generated property
  2. Invoking code manually to update a property to make sure update notifications are firing
  3. Change a value using a Control of some kind to make sure TwoWay binding is updating the instance 

These goals can be met with a simple and unglamorous user interface:

<Grid x:Name="LayoutRoot" Width="450" HorizontalAlignment="Left">
      <StackPanel>
          <TextBlock FontSize="30" FontFamily="Verdana">Things that I have time for:</TextBlock>
          <TextBlock Text="{Binding Code}"></TextBlock>
          <TextBox Text="{Binding Wine, Mode=TwoWay}"></TextBox>
          <Border CornerRadius="5" BorderBrush="Red" BorderThickness="2">
              <Border.Child>
                  <TextBlock Text="{Binding Wine}"></TextBlock>
              </Border.Child>
          </Border>
          <Button x:Name="ChangeBtn" Click="ChangeBtn_Click" Content="Change"></Button>
          <StackPanel Orientation="Horizontal">
              <TextBlock>Money(double)</TextBlock>
              <TextBlock Text="{Binding Money}"></TextBlock>
          </StackPanel>
      </StackPanel>
</Grid>

Yes, I’ve identified Code, Wine, and Money (and little else) as things that I have time for.  You’ve got to write what you know.  In the Loaded event handler for this basic Control, we can see the Entity Value classes in action.  The first step is to create a simple model to generate a bindable Type from.

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    var model = new AttributeViewModel();
    model.Add(new HandWaver.AG.EVModel.Attribute(0, "Wine", typeof(string)));
    model.Add(new HandWaver.AG.EVModel.Attribute(1, "Code", typeof(string)));
    model.Add(new HandWaver.AG.EVModel.Attribute(2, "Money", typeof(double)));

First we’ll try one object with three attributes.  Creating an instance of the dynamic type looks like this:

var t = BindableEVBuilder.GetDecoratorType(model); _entity = (EntityWithAttributes)Activator.CreateInstance(t);

var t =  BindableEVBuilder.GetDecoratorType(model);
_entity = (EntityWithAttributes)Activator.CreateInstance(t);
_entity["Wine"] = "Chateauneuf du Pape";
_entity["Code"] = "Silverlight";
_entity["Money"] = 5555785.0;
LayoutRoot.DataContext = _entity;

Time for the moment of truth.  Running the code and interacting with the UI yields the following:

UI0

Everything works.  The one time binding “Silverlight” works, I typed Malbec in the TextBox and it updated the object, the Property changed evens fired, and clicking the Change button changed the bottom text to 1000000.  My dynamic property system works.

Going a Little Further

The basic binding situations work, but what about a slightly more complex scenario?  Let’s go ahead and test multiple dynamic types, multiple instances, and IValueConverters.

void BindGrid()
{
    var carModel = new AttributeViewModel();
    var year = new HandWaver.AG.EVModel.Attribute(0, "Year", typeof(int));
    var make = new HandWaver.AG.EVModel.Attribute(1, "Make", typeof(string));
    var model = new HandWaver.AG.EVModel.Attribute(2, "Model", typeof(string));
    var series = new HandWaver.AG.EVModel.Attribute(3, "Series", typeof(string));
    var msrp = new HandWaver.AG.EVModel.Attribute(4, "MSRP", typeof(double));
    carModel.AddRange( new List<HandWaver.AG.EVModel.Attribute>() {year,make,model,series, msrp} );

    var carType = BindableEVBuilder.GetDecoratorType(carModel);

    var wrx = (EntityWithAttributes)Activator.CreateInstance(carType);
    var s4 = (EntityWithAttributes)Activator.CreateInstance(carType);
    var s4Prestige = (EntityWithAttributes)Activator.CreateInstance(carType);

    year.SetValue(wrx, 2002);
    make.SetValue(wrx, "Subaru");
    model.SetValue(wrx, "Impreza");
    series.SetValue(wrx, "WRX");
    msrp.SetValue(wrx, 26000.00);

    year.SetValue(s4, 2010);
    make.SetValue(s4, "Audi");
    model.SetValue(s4, "S4");
    series.SetValue(s4, "Premium Plus");
    msrp.SetValue(s4, 47900.00);

    year.SetValue(s4Prestige, 2010);
    make.SetValue(s4Prestige, "Audi");
    model.SetValue(s4Prestige, "S4");
    series.SetValue(s4Prestige, "Prestige");
    msrp.SetValue(s4Prestige, 53000.00);

    var carList = new List<EntityWithAttributes>() {wrx, s4, s4Prestige};
    CarGrid.ItemsSource = carList;
}

You can see that there’s a bit of code being written to create the instances and set the values, but we could obviously write more code around that to automate more of the tedious work.  I will also note that AutoGenerateColumns=”True” did not work on the DataGrid: I leave that as an exercise for another day.  The resulting display is exactly what you’d expect:

UI1

 

A little polish

When first testing this code, I could see that it worked but inspecting the dynamically generated EntityWithAttributes descendant was producing odd results in the Visual Studio debugger.  Even trying to add a watch for the base class would show an error like “Unable to evaluate expression”.  Silly rabbit, I had forgotten to include debug information in my Reflection Emit code.  This turned out to be a lot easier than it sounds.  Let’s take a look at the EnsureDynamicAssembly method that I skipped earlier.

        /// <summary>
        /// Debugger info found at http://blogs.msdn.com/jmstall/archive/2005/02/03/366429.aspx
        /// </summary>
        static void EnsureDynamicAssembly()
        {
            if (null == _dynamicName)
            {
                var appDomain = AppDomain.CurrentDomain;
                _dynamicName = new AssemblyName("HandWaver.AG.EVModel.TypeDecorator");

                _aBuilder = appDomain.DefineDynamicAssembly(_dynamicName, AssemblyBuilderAccess.Run);
#if DEBUG
                var debugAttrType = typeof(DebuggableAttribute);
                var debugAttrCtor = debugAttrType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });

                var customAttributeBuilder =
                    new CustomAttributeBuilder(debugAttrCtor,
                        new object[] { DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default });
                _aBuilder.SetCustomAttribute(customAttributeBuilder);
#endif
#if DEBUG
                _moduleBuilder = _aBuilder.DefineDynamicModule(_dynamicName + ".dll", true);
#else
                _moduleBuilder = _aBuilder.DefineDynamicModule(_dynamicName + ".dll");
#endif
            }
        }

I don’t usually use preprocessor directives but this is exactly what they’re for.  The stuff in between the #if DEBUG statements includes some symbol information in the dynamic assembly.  There’s more work I could have done to associate the code to a Document for source step-through, but at least going this far gets my Local/Watch windows in VS working:

WatchWindow

You can see that I can evaluate properties on the base class and even Reflect the dynamic type to see that it exposes “real” properties like any other Type.

Conclusion

There is a saying that every problem in computer science can be solved with one more level of indirection.  When using the Full .NET Framework it often seems they’ve thought of everything, even providing an effective layer of indirection for Reflection in the form of TypeDescriptor and friends.  Lacking TypeDescriptor in Silverlight, it’s up to us in the community to come up with solutions while we simultaneously pester Microsoft to add more extensibility to the Data Binding frameworks.



Monday, September 07, 2009 12:59:55 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [5]  |  Trackback
 Saturday, August 15, 2009

I have been happily using the Unity container for over a year now.  I had previously written my own IoC framework in Silverlight and used some other off the shelf and custom home-grown containers.  I have recently been getting started using MEF in Silverlight as part of some up and coming Patterns articles.

When you scratch the surface of MEF, I’ll warn you that you may be Underwhelmed.  What, exactly, is this?  The Ultimate IoC container?  What is this doing for me that Unity wasn’t already doing for me?  In fact, you can implement the IUnityContainer interface with MEF so what’s the big deal?

Is the big deal…

  • That MEF is the Visual Studio 2010 extensibility mechanism?  No. Microsoft has claimed that they needed MEF for internal efforts like this.  I believe they are earnest, that this is not just a public “Look at us eating our own dogfood” showing.  Still, Microsoft needed the Entity Relation model beneath the Entity Framework and we saw how well that was received by the community.
  • That MEF works in Silverlight?  No.  Other IoC containers were ported to Silverlight 2 long before Unity or MEF.  We’ve been able to use the same container for Silverlight/WPF/ASP.net/Winforms/Console apps for a long time.
  • That MEF has cool features like Catalogues, Dynamic Recomposition, Lazy<T> ? No.  These features are cool and I plan on exploring them further and talking about them to anyone who will listen.

No, the big deal is that MEF is shipping with .NET 4.

So what, you say? Let me explain.  A lot of you probably listen to .NET Rocks.  I do, I enjoy it.  The hosts are funny, the guests are bright, and I get bite-sized updates on what is going on out there in areas of the development universe that are important to me but not so important as to be in my overloaded RSS list.  .NET rocks succeeds for various reasons and to hone in on one of the big whys let’s take a look at one possible way to group developers:

  1. Brand new developers. 
  2. Developers who are lazy clock-punchers who don’t care about their craft whatsoever.  Enough said about these folks.
  3. Developers who know enough to know there are better ways.  They struggle within the bureaucracy.  They’ve heard testing is good, but why?  They feel they probably need abstractions, but where?  Some don’t quite have the motivation or the skills the find the answers themselves; some have never been afforded the opportunity to break out.
  4. Developers who think they have all of the answers but are full of $(‘.crap’).
  5. Developers who mostly “get it”, who have the motivation and skills to find the answers, refine their craft, and make things better.

Based on my own experience Group #3 makes up an awful large percentage of the developer world.  A lot of the folks in Group #5 start here until something snaps within them and they decide to stop playing WoW and get serious about figuring out what it takes to get better.   These #3 folks want to learn but the lure of American Idol keeps them from catching up on those blogs.  They want to try a new pattern but the Architecture Police have decreed that they must never do X and always do Z.  Maybe the political war required to get a new library into the solution to try a different way kills any initiative.  Maybe their employer never springs for training.  More often than not, the high turnover in IT isolates developers from the long term perspective that would otherwise be a great teacher.  Which abstractions worked and which turned out to be nightmares or at best simply unnecessary?  Who knows.  We don’t go back and ask because we’re afraid of the answers, and to be fair we all hate each others’ code anyway.

The .NET rocks show and things like it is a little beacon of light, a reminder that some people are really doing things right out there, and staying on the cutting edge, and delivering a lot of value.   But, Damon, how does this relate back to MEF?  Because Group #3 is looking for guidance.  How many guests have debated which Data Access technology Microsoft “wants us to use” ?  Do they want me to use LINQ to SQL or Entity Framework?  Yes, the good folks behind door #3 who are in the .NET space overwhelming look to Microsoft for that guidance.  When Microsoft showed creating SQL DataAdapters inside button click event handlers that’s what they did.  When Microsoft said Stored Procedures are the way that’s what they built.  When Microsoft said SOA was good we learned SOAP.  When Microsoft endorsed jQuery we learned jQuery. 

By putting MEF in the .NET framework the community of well-meaning folks who want to do better are going to see a new message, some new guidance.  “Microsoft wants me to think of my applications differently.”  Microsoft is telling me that my apps should be composed out of modules, perhaps modules hidden behind interfaces.  I should worry about the physical location of a module or its implementation later and program against abstractions.  When I write a class I should think about what the responsibility of this class is and what its dependencies are.  Microsoft is telling me to get onboard with loose coupling.  I don’t need to petition my overlords to bring in a new framework because the only thing between me and MEF is:

using System.ComponentModel.Composition;

Microsoft has always been a Platform company.  I like my Zune, the Xbox is cool, I’m a PC, and maybe the Microsoft Stores will be cool.  But let’s be real: what Microsoft does better than anything else is to build something that other people use to build something.  By including MEF in the core toolbox Microsoft is getting behind a lot of solid development ideas and removing another barrier between the Average Corporate Developer and Better.

 



Saturday, August 15, 2009 7:30:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Tuesday, July 14, 2009

One natural way to create some visual effects would seem to be animating the clipping path of a visual element.  Sitting down in either Visual Studio or Blend 3 will immediately show there’s not a straightforward way to do this.  There have been some other means of doing this posted online involving  creating a Storyboard and DoubleAnimation entirely in a code-behind.  Since one of our goals when using Silverlight and Blend should be a clean designer/developer separation,  I didn’t care for this approach. 

We’re going to build a “wipe” effect using animation and clipping paths and the only code behind will be the Storyboard trigger.

Setup

I’m first going to create a Silverlight 3 Navigation application and throw in my own styles.  I add a Page called AnimateClip.xaml and throw in a DataGrid containing some sample wine data and a button I can push to test the “wipe” effect.  The application looks like this when I navigate to the new page:

ss0

 

DataGrid XAML

I’m going to apply the Wipe effect to the DataGrid.  Here’s the initial XAML defining my grid.  As you’ve already seen above I created some Sample Wine data to populate the DataGrid.

<data:DataGrid x:Name="WineGrid" AutoGenerateColumns="True" IsReadOnly="True" CanUserResizeColumns="True" Grid.Row="1" Width="500" Height="200" RenderTransformOrigin="0,.5">
    <data:DataGrid.Clip>
        <RectangleGeometry Rect="0,0,500,200">
            <RectangleGeometry.Transform>
                <ScaleTransform x:Name="WipeScale" ScaleX="1" ScaleY="1"/>
            </RectangleGeometry.Transform>
        </RectangleGeometry>
    </data:DataGrid.Clip>
</data:DataGrid>

Note that I’ve given the DataGrid a clipping geometry that exactly matches the bounds the DataGrid has anyway.  The RectangleGeometry gets its dimensions from a Rect property.  The struct Rect has a Width property, but Rect.Width does not appear to be backed by a DependecyProperty, so we can’t simply animate the Width of a Rect.  Without creating new Rect structs and manually animating in C#, some trial and error was needed in order to find a workable XAML-only solution.  The solution is to name the ScaleTransform and animate its Properties.

I’m going to create the Storyboard manually in XAML, we’ll see why when moving to Blend 3 in a minute.

<Storyboard x:Name="WipeGrid">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="WipeScale"
                                   Storyboard.TargetProperty="ScaleX">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
        <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="0"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

So, this is fairly simple once we figure out how to effectively animate the bounds of the DataGrid.  Ordinarily this Storyboard would produce a uniform “shrink in” effect.  The default RenderTransformOrigin is of course the very center of a UIElement.  Because the RenderTransformOrigin of the DataGrid is set to 0, .5 we get the desired “wipe” effect as we are calculating from the left side rather than the center.

When I press the Wipe Out button the code-behind starts the Storyboard.  The wipe effect now works as desired.

Polish

As I enjoyed how the wipe effect looked, I thought perhaps I’d use some of the new built in easing functions to make it even better.  In the recently released Expression Blend 3 + SketchFlow, this is what I see when attempting to edit my Storyboard:

ss1

Despite the fact that the Storyboard works,  the clipping path is missing something needed for Blend to be able to show it for timeline editing.  I assume this is because it’s technically not a visual element in the tree, but just a humble RectangleGeometry used to modify a visual element.  I really don’t feel like learning the ins and outs of all of the easing functions and their parameters, so for now I had to create a bogus storyboard and copy it to this Page.  The Quadratic Ease (InOut) produced the effect I was going for.

<Storyboard x:Name="WipeGrid">
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="WipeScale"
                                   Storyboard.TargetProperty="ScaleX">
        <EasingDoubleKeyFrame KeyTime="00:00:00" Value="1">
            <EasingDoubleKeyFrame.EasingFunction>
                <QuarticEase EasingMode="EaseInOut"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
        <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="0">
            <EasingDoubleKeyFrame.EasingFunction>
                <QuarticEase EasingMode="EaseInOut"/>
            </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

So, while that would not be bad as far as hand-crafting XAML it would be better if I didn’t have to build fake Storyboards to create my visual effects.  With a more complex Storyboard mistakes might be made in the manual copy & conversion process.  You now have an alternate way to animate clipping paths in Silverlight using XAML.



Tuesday, July 14, 2009 7:46:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 05, 2009

The Fox Valley .NET user’s group has posted a hand-out for the two sessions I’m doing this Saturday.  Cool!

http://fvnug.org/dnn/LinkClick.aspx?fileticket=ZGv%2fajN89eU%3d&tabid=36

{Edit: Here's the schedule of events too. http://fvnug.org/dnn/DayOfNet/Schedule/tabid/62/Default.aspx. I hope to see familiar faces there tomorrow.}



Tuesday, May 05, 2009 2:35:13 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, May 01, 2009

The next two stops on the Mix it Up! tour are quickly approaching.  My talk to the Wisconsin .NET Users Group (metro Milwaukee area) has been moved up to this coming Tuesday, May 5th. You can find details on how to register and where to go here.

The following night, Wednesday, May 6th, I will be in Madison.  You can find details on this talk here.

I hope to see you there!



Friday, May 01, 2009 8:00:22 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, April 10, 2009

Last night I did my first stop on the Mix it Up! tour: the Indy NDA group in Indianapolis, IN.  These guys have got it made.  They have an absolutely fantastic group of people, a great location, and a TON of swag at every meeting.  I was pleased to be bringing some t-shirts and copies of Expression Studio only to show up abd find 20 books, a webcam, and various other nice prices already on the swag table.

These guys are hard-core too:  Their attendance is 120 people and up for every event, and they hold various SIG groups right after the main user group meeting.  After I did the Mix it up content they invited me into their Architecture SIG meeting to discuss the MVC pattern and we ended up talking about map reduce and the Parallel Extensions for the .net framework.  Thanks, guys, for having me, and maybe I’ll be back again.



Friday, April 10, 2009 2:59:59 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, March 31, 2009

The What:

A whole lot of goodness was announced at MIX09.  Many of us were unable to attend.  Larry Clarkin and Dave Bost of Microsoft decided to locate some dedicated Web/RIA geeks in the Midwest region to bring an ultra-condensed version of the MIX09 announcements to user groups, conferences, and code camps.  While the level of detail won’t equal what you would have gotten by going to MIX09, we can hopefully get you excited about what’s coming up and answer some of your questions. 

The Who:

Corey Miller

Anthony Handley

Damon Payne

Josh Holmes

Larry Clarkin

The When:

  • 4/1 CD2UG (Corey Miller / Anthony Handley) – The first stop, I’ll be heading down to Chicago tomorrow to provide moral support and take notes on how things flow.
  • 4/9 Indianapolis, IN (Damon Payne)
  • 4/15 CNUG (Corey Miller/ Anthony Handley/ Josh Holmes)
  • 4/30 Lake County (Anthony Handley)
  • 5/6 Madison, WI (Damon Payne)
  • 5/8 RIAPalooza (Anthony Handley)
  • 5/9 Fox Valley Day of .NET (Damon Payne/ Larry Clarkin) – This is a day long conference, and our presentation will serve as the keynote for this event!
  • 5/12 Milwaukee (Damon Payne)
  • 5/12 Ft Wayne, IN (Corey Miller)
  • 5/14 Chippewa Falls, WI (Damon Payne) – hopefully I can be forgiven for looking forward to this date most of all.  Doug has promised to book the Leine Lodge for this presentation.  Beer + Silverlight = shangri-la
  • 5/16 Indy Code Camp (Josh Holmes)
  • 5/19 South Bend, IN (Corey Miller)
  • 5/26 Rockford, Il (Josh Holmes)
  • 5/30 Chicago Code Camp (Josh Holmes – possibly others?)

See you there!



Tuesday, March 31, 2009 9:11:15 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, March 19, 2009

Obviously a lot of big things were announced at MIX 2009 yesterday.  I maintain my position that I would like to see Silverlight go towards more parity with WPF than ASP.Net, but there’s plenty to be happy about here.  I am most interested in the low-level details on the Bitmap APIs, perspective 3D, and the new tool bundled in with Blend 3. 

MIX it UP!

If, like me, you missed MIX because you couldn’t spare the time or expense, we have a consolation prize to offer you.  Larry Clarkin has organized a cabal of Silverlight-loving speakers in the Midwest with the mission to bring the presentations from MIX2009 to your local User Group, Code Camp, or other community event.  The “MIX it up” tour may already be planning on visiting your user group in MN, WI, IL, or IN.  I myself will be talking at about four stops on the MIX it Up! tour.  Look for more details and dates soon.



Thursday, March 19, 2009 11:15:52 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, March 13, 2009

I’ve been blogging since before it was called “blogging”, I started around 1998 on a Geocities site.  I like browsers.  The internet is awesome.  Web pages are great.  Web pages have literally changed the world.  Still, call me old fashioned, but I like Smart Clients.  Whether you call them “Smart Clients”, “Fat Clients”, or “Client Server Applications” – they can often still offer the best user experience and the most rewarding developer experience out there.

In the ‘90s and ‘00s there were various reasons why companies were going online.  A lot of it was hype, to be a part of this big movement that was going on.  Some businesses found that some of their worst application deployment nightmares could be avoided by using the browser as a delivery mechanism.  Some businesses found that a standards-compliant web page could (sort of, with a lot of pain) be used to reach a wider audience such as Mac or Unix users.  Some businesses found that having things like database connections behind the firewall was a Good Thing. 

ReturnoftheSmartClient

Not all is well on the Web

Despite outrageous success, not everything is great in the land of browser based applications.  Is the in-browser markup-based application the best choice or is it being carried forward purely by momentum?  If someone at your business announces that “We’re going to build a new Widget Widgetizer for our Agents”, is it an unspoken assumption that it will be delivered via HTML?  Is it cheaper and easier to build, debug, deploy, and maintain a browser based app than a Smart Client application?  I wonder.

Doing layouts for web sites is still painful.  HTML was not precisely meant to be a ubiquitous content-positioning mechanism.  The post-<table/> world can be infuriating because CSS is still painful.  Successfully doing CSS-only layouts seems to require Herculean efforts.  Sure, people do it all the time, but these skills seem to be very hard won.  The average CSS expert I talk to can rattle off an astounding list of browser specific gotchas and most will confess that testing is extremely time consuming.  Firefox seems to mostly get it right, but that doesn’t matter if Safari and IE don’t.    Hilariously, IE8 will get most things right but this is a curse in disguise: all of the server-side “if browser is IE” code out there will potentially now break under IE8.  Even the dynamic menus generated by ASP.Net (a Microsoft product) were broken in the first IE8 beta, and appear to be broken still in the first release candidate.  Maybe it’s just the way my mind works, but I’d rather troubleshoot a threading issue than try to figure out which CSS attributes function differently on which dom objects in which browser and scream about min-height:xx; being ignored.

HTML 5 promises to save us with real layout primitives, but if we can’t even get rid of IE6 after 7 years, what kind of adoption timetable can we expect with a whole new paradigm?

Doing browser-based development using Ajax and JavaScript is still painful.  If you don’t believe me  I have a challenge for you: turn on your browsers JavaScript error notification so you get a popup every time a script error occurs.  How long can you stand to surf like that?  I personally last about 25 seconds.  Why do people tolerate this?  Name an important application commonly used outside the browser where this level of scary flakiness would be tolerated?  Would iTunes be as popular if I occasionally had to “refresh” the application because a error occurred when I hit Play?  If Live Messenger randomly threw error codes up?  If Excel occasionally just wouldn’t save my spreadsheet?

The Internet, which in its current incarnation was designed around stateless ideas, is being used to deliver applications which need to represent state to the user.  It does this by delivering documents with complex layouts written in languages that were not meant to allow for complex layouts, supplemented by scripting languages pushed to the breaking point.

Not everyone likes strongly typed languages, true.  Not everyone likes writing unit tests, with code coverage tools, refactoring tools, static analysis, and so forth.  A lot of people do, and a lot of those people find the typical JavaScript experience to be a bit primitive by comparison.

iPhone as indicator?

When the iPhone was first announced, the plan was that development for the device would be accomplished via JavaScript in the browser with special extensions to access the iPhone hardware.  Ultimately, though, development is done as a native client in Objective C or Mono static compile.

I had, for years, secretly held the theory that Microsoft avoidance was the primary factor that had propelled browser-based development in the direction it was going.  Building native apps for the various LINUX flavors isn’t all that fun.  Java Swing is absolutely terrible.  Visual Basic, C++, or .NET on Windows? Pretty good!  Personally, if I wanted to build an application that could reach over 90% of PCs in America, and have a great developer experience while doing so, I’d say that’s a pretty good bet.  A lot of people disagree with me.

With the iPhone having gone native with Cocoa Touch, and Google re-imagining ActiveX via “Nclient” I wonder if we are seeing the beginning of a trend.

Silverlight to the Rescue?

I was meeting with a potential client who seemed to be somewhat familiar with some of my on-line antics.  The client asked “So, why are you so into Silverlight?”.  There are really two answers to this question.  One of course is that my Nerd Brian gleefully laps up the serotonin released as a side effect of my diet of C# 3, VS2008, LINQ, Lambdas, vector graphics, and so forth.  This is not an answer that lends itself well to building a proposition of the business value of your expertise.  So what came out of my mouth was something like this:

If we take a look at the application designs and user experiences we are seeing in the current “web 2.0” world we can make some observations.  We are seeing an amazing level of creativity and high production quality of graphics and animation.  We are seeing instant interaction, multiple simultaneous asynchronous actions happening by exchanging small messages with the server instead of whole-screen refreshes.  We have Google maps and several “Outlook in the browser” variants and a host of other accomplishments I wouldn’t have believed without proof.  The technologies allowing us to do this are all in one way or another hacks, round-about techniques, unintended extensions, or fragile houses made of cards.  They are steps towards real Smart Client technologies.  They are all band-aids and medications lavished on a ruined Soldier who was never meant to fight this war.  I prefer to take the most direct route and use a tool perfectly suited to the types of experiences we want to create.  Silverlight is the direct route from A to B.

This is the point where people who have worked day in/day out with JavaScript, Ajax, and CSS for ten years will tell me that they can do anything that Flash can do, and that it’s not that hard, and browser plug-ins suck, etc.  I have a hard time understanding this world view, and I suspect that a great many other people lacking that 10 years of scars might as well.

What’s your point?

At any rate, my goal here is not to start a war.  Rather, let’s pretend your business is actually having a real discussion about whether an application should be browser based or not.  What does the landscape look like today?  I’ve already made some comments about the developer story, but what about:

Data, Firewalls, and you

I was serving as technical reviewer for a book called “Apache SOAP”, before SOAP became somewhat synonymous with “Web Services”.  It seemed clear that Http-based message exchange could potentially solve one of the issues associated with the client-server era.  The firewall is already open for HTTP traffic, so why not send data instead of markup?  There are a number of options today for exchanging data through the firewall: WCF, Remoting, REST-full services, ASMX services.  Not only does this negate one of the old benefits of markup-based applications, but a lot of things are going the direction of distributed computing, grid computing, or mashups, or crowd-sourcing.  The success of Folding @Home, for example, shows what a distributed auto-updating smart client can do.

Performance

I often hear the words “Performance doesn’t matter”, mostly from people for whom performance is a black eye on their world view.  Performance does matter.  I currently have 250 movies in my Netflix queue and simply scrolling the page up and down in IE maxes out the CPU.  Pulling up damonpayne.com in Firefox and resizing the browser window maxes out the CPU.  Yet in Silverlight I can play full-screen HD video and the CPU is around 25%.  Animations? Visual Tools? Large data sets?  What about callbacks to a client without the client needing to constantly poll?  I suppose network performance doesn’t matter either?  In case you haven’t noticed, CPUs aren’t getting faster at the same rate they have been.  Performance matters, and the compiled language camp has a big advantage here.

Deployment

Through various techniques, it seems to me that the deploy-and-update issue has mostly been solved.  Java had Java Web Start.  There is a slew of aftermarket “Application Updaters” for various platforms.  .Net had the Application Updater Block and now Click Once and XBAP.  A rich Silverlight (or Flash) app can still be delivered through the browser but keep the advantages of a Smart Client platform.  PERL has CPAN.  Vista has Windows Update.  In this late hour, what kind of deployment advantage can we say a web application has over a smart client?

Cross-Platform web apps

I feel the need to reiterate this point as it’s a personal favorite: How cross platform are markup based applications?  How much time is spent debugging CSS and JavaScript in different browsers on different operating systems?  Chances are it’s a lot of time that could have been spent elsewhere.  Sun tried to make Java the universal smart client platform but they forgot to to make AWT and Swing not suck; SWT seems to have gotten to the party too late. 

Standards (HTML, CSS, ECMA script), no matter how well specified, will somehow manage to be interpreted differently by different vendors.  The nice thing about a plug-in model (Silverlight 2, Flash) is that they tend to come from a single vendor for every browser and operating system.  Most of the code will be shared with a bare-minimum bootstrap rebuilt for the specific platform.  There are some exceptions, such as Moonlight. In the case of Moonlight, Miguel, of whom I am a huge fan, actually has access to Microsoft’s internal specification and test suites.  A spec PLUS a suite of tests that shows you if you are rendering correctly is a good thing.  I have much more confidence that Microsoft and Novell can get the Silverlight experience to be 99.9% universal than I do that IE/Firefox/Opera/Safari/Chrome will come close to converging.

Presentation

As I mentioned to my client, it seems a shame to me to spend a lot of time and money producing high quality assets and then Hacking them up for a web site.  Worse, if someone has their browser scaled for accessibility reasons, raster images aren’t going to look so hot.  Vector graphics presented via a smart client technology has a clear advantage here.  A Style or Control Template in Silverlight does precisely what it’s supposed to do, no frustrating cross-browser debugging.  No need to build raster images for Gradients when Gradients are primitives within Silverlight.  No need to debug layouts in every browser when Silverlight has a comprehensive yet extendable layout system.  No need to worry about “web safe” colors, and you need not be shy about embedding fonts.  I’ve seen some impressive JavaScript-based animation, but Expression Blend makes it so easy and there’s that pesky “performance” thing to think of too.

Smart client software can give you great control over the presentation of your brand.

Conclusion

After 10 years of the browser delivered/markup based application getting all the attention I think the Smart Client is making a comeback.  Smart Client technology has gotten better.  Having massive storage and gadgets like GPS and accelerometers in our phones has brought back to the mind the advantages of access to the local system.  Ideas like the Apple Store help close the usability gap between installing software and just hitting a webpage.  Standards have emerged letting Smart Clients take advantage of the web.

Part of what I’ve said here can be chalked up to personal preference.  If you like dynamic languages and don’t write unit tests, or you hate Microsoft, or you are anti plug-in, you may disagree. I would appreciate any rational feedback pointing out where you think I’m wrong.

Note: As I was doing proofreading for this article before publication, Scott Hanselman posted some thoughts about Quake Live.  At one point he states “There's no reason for QuakeLive to be shoe-horned into a browser plugin”.  I couldn’t agree more.



Friday, March 13, 2009 2:14:11 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Tuesday, February 24, 2009

I just learned that my Image Hotspot Designer article was mentioned on TCS Weekly #005:

http://channel9.msdn.com/shows/TCSWeekly/ep005/

The article is mentioned briefly around 2:30 in the video.  Now the entire world knows about my love of wine and my messy (if well supplied) office.



Tuesday, February 24, 2009 10:22:10 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, February 23, 2009

I have taken first place in the most recent Silverlight: Write and Win contest on SilverlightShow.Net for my article on creating a Designer for Image Hotspots in Silverlight.  Thank you judges!



Monday, February 23, 2009 9:53:31 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, February 06, 2009
 Friday, January 23, 2009

I had to comment on the latest Hanselminutes podcast.  I would absolutely love to do an article in the same style as AGT, but building up a Document instead.  I have not written a document/text editor from scratch so I would be starting from zero knowledge, but it sure sounds like fun.

There's at least 10 more AGT articles to go, so don't hold your breath.



Friday, January 23, 2009 1:42:25 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, January 14, 2009

I wanted to write up some thoughts based on attending yesterday's MSDN Dev Con in Chicago.  Since I knew this was coming, I purposely did not do much reading about the technologies announced at PDC.  This was my first exposure to these items. 

Keynote: Ron Jacobs's keynote was of course the typical "Lots of cool stuff you can't have yet".  I'm interested in Windows 7, I'm one of the folks who actually really likes Vista.  While I had hear about VS 2010 being rewritten in WPF this was the first time I had actually seen it, in this case showing some kind of comment view provider.  This will be huge.

A lap around Oslo: I've been following Dan Rigsby's blog for a while and I got a chance to meet him before the show. 

Here's what I learned from his talk: Oslo is the capital of Norway, and Microsoft wants to buy it.

Just kidding, Dan!

Now that I have a super-basic understanding of Oslo I have a couple of concerns.  The first regards Dan's comment about creating a DSL that some kind of business user could use to create functionality.  It is my firm belief that this won't happen in the next ten years, not because it's technically infeasible, but because Business Analysts, Managers, and the like do not want direct responsibility for systems.  They like a nice, thick neck to get their hands around if something goes wrong and by that I mean us Technical folks can always be blamed for any shortcomings in the implementation of any Grand Vision.  Maybe I'm pessimistic, but I cannot imagine this direct accountability happening any time soon.

My second concern is a smaller technical issue.  Dan showed an example of a DSL specific to WCF services.  This seemed well enough for expressing WCF specific ideas (endpoints, URL patterns, etc.) but I wonder if there is or will be a mechanism for using generic code from another CLR language.  For example, I may have a business logic or data access component already written in C#, and my WCF service is just a thin layer on top of it to expose it as a service.  Enquiring minds want to know.

Business Apps in Silverlight: I heard before the conference that this talk would involve a brief look at some new features in Silverlight 3 so I had to check it out.

The future stuff was billed as ideas taken from the Artist Formerly Known as Alexandria.  Overall, I'm sorry to say I was disappointed in what I saw and here's why:

  • A demo was shown whereby a server side business operation exposed via WPF was automatically linked to a generated Silverlight class in the client.  This was nice, since I have nothing but issues with the automatically generated endpoint configuration for WCF <--> Silverlight.
  • Data Source: MSFT is bringing the notion of an ASP.Net Data Source into Silverlight/XAML.  All in all, I wasn't sure I liked the magical nature of this, but it's optional.
  • Navigation: my ears perked up when the speakers said they were going to bring a notion of Navigation into Silverlight.  My problem with what was shown was that it was NOT NavigationWindow and Page, but something new: Frame and so forth.  Why not use WPF concepts?  I have heard many times that the intention is to bring more parity between Silverlight and WPF.  The ability to deep-link to the application using the URL query string is good at least.
  • An ASP.Net-ish Login control was shown as well as some declarative security you can place on functionality.  It wasn't clear if this would ONLY work with ASP.Net Membership and Role providers on the server, or if the client side mechanism would be extensible via a provider model as well.

Overall, I'd like to see Silverlight going in more of a WPF direction than an ASP.Net direction and I'm worried about what I'm seeing.  The vibe I got from this talk was that Silverlight is going to "Work real well with ASP.Net" or "Something you can do instead of Web Pages, if you want".  There was no mention of bringing Commanding or other awesome (fundamental) WPF features into Silverlight.  I hope that I'm wrong.

F#: I first looked at F# something like two years ago and got frustrated and dropped it.  Having done some functional style stuff in C# and LINQ of late, I've been meaning to pick it up.  Aaron Erickson gets big points from me for using the term "Hand Waving".  His presentation, however, I felt wasn't basic enough for an intro to F#.  If the goal was to tell the audience why they might want to look into F# then mission accomplished.  If his goal was to show us how to do some basic things, not so much.  What do the |> or -> operators mean in F#, things like that.  By this time of the day, my 100% lack of sleep the night before was seriously weighing on me, so these things may have actually been explained.

I do plan on getting the book he described as the Most Basic learning F# book he showed, if I can remember what it was called.

After the conference several of us went to Fogo de Chao where I had a tremendous amount of excellent meats with bell peppers and some Malbec.



Wednesday, January 14, 2009 11:51:59 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, January 12, 2009

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

 

Gestures, Commands, Transactions, and Undo

There's so many sexy things coming up, it was difficult to postpone them further.  There's two more important categories of plumbing that needed to be built.  We'll cover the design of one category and its pieces in this article followed by two dedicated implementation articles.  The other functionality, Document Types and Serialization, will be next.

I would like to be able to use the keyboard for some gestures on the design surface: for example the arrow keys should move the selection and I should be able to delete items from the surface with the delete or use CTRL-Z for undo.

Additionally, I would like to support some kind of undo.  The plumbing needed for undo will allow for other cool interactions later...

Implementing Undo using Transactions and Commands

Undo can be an incredibly hairy thing.  In my opinion, going back to a working system and suddenly trying to add undo can be a very good test of how well designed the system is.  Those following along should take careful note of the degree to which the changes we see are additive (feels like we're just adding another feature) versus things that are refactoring (changing code that was already working to support this new feature).

Now to reveal a personal bias: I seldom find a use for "Redo" as it is sometimes implemented.  For example in MS-Word you can apply some formatting to text.  You can then use "redo" to apply the same formatting to some other text.  I'm really only interested in in redo as an Undo-for-Undo. So Move something, undo, no wait I really wanted to do that, redo.

This is something that's important to get right so let's list the primary goals:

  1. The changes made to items on the surface are easily captured to be undone or redone.  This should be true for both surface interactions and property editing.
  2. The number of undo levels should not be artificially limited. In some cases an undo won't "work" because the state of the system has changed -  we don't want Units of Undo to have to know about other Units of Undo.
  3. There should be a centralized means of manipulating, creating, or querying currently known Units of Undo.
  4. Interactions should be able to be grouped together where it makes sense to do so.  For example, moving an IDesignableControl around on the surface may in fact be 200 small changes, but we really only care about the starting position and the final position when the move interaction is over.

Item #4 in particular is important to me.  Visual Studio sometimes has some odd behaviors where what is perceived as a single Gesture by the user actually requires several Undo operations to erase.  For example, I might paste some code in or use a shortcut Chord and the first undo changes the formatting of the created code and the second undo actually gets rid of the code.

 

Gestures and Commands

Would it be best to try to mimic the Commanding system from WPF, even partially?  I debated this point long and hard: is it worth some research, some effort, some potential confusion due to subtle differences?

I played around on several different occasions and I did come up with some things that I liked better than the other "Commanding in Silverlight" code I've seen out there but for now I didn't want to use it.  Specifically, the ability to map keyboard gestures to a command from XAML was problematic.  Still, Silverlight does contain the ICommand interface, and I tend to like the Command Pattern for encapsulating units of work, so by this time I had most of a design in mind:

UndoTransactions

Controls that need to affect the change of something living on the Design Surface will go through some kind of Change Service.  This is similar, but not exactly like, how Visual Studio does this today.  Using this design I will allow interested parties to be privy to (but not cancel) all the changes going on in case this is needed for some custom logic.  The IDesignerChangeService will also be the gateway to creating and undoing transactions.  This bears some disucssion.

The IDesignerTransactionService and IDesignerChangeService are both public and overridable or replaceable, but they work in tandem.  In any circumstance I can immediately think of, client code will want to deal strictly with the change service.  The process will look like this:

CommandChangeProcess

 

Note that it will be up to the Client who is initiating the change to determine if gestures need to be grouped together into a transaction or not.  No one else would know!  We'll explore more about how we accomplish this in the forthcoming implementation article.  The stimuli shown here are not going to map directly to real method calls, but this gives you a good idea of what's going to happen as objects are edited.

I do like the way WPF creates some ways of specifying commonly used UI commands.  I can also see how the ability to customize the mapping from gestures to specific ICommand implementations would be useful.  Towards these goals, I am going to build some infrastructure modeled after what's in WPF.

DesignerInputBinding

These classes all exist in WPF.  My goal here is that I will mimic the WPF functionality as closely as possible and provide a public interface to InputBindingCollection.  With this, an application that wishes to customize the keyboard behavior of the design surface can simply replace the default ICommand for a gesture.

 

AGContrib

Over the course of the AGT project and several other efforts, I've written (or at least started) some useful things for Silverlight that may have usefulness beyond the AGT effort.  I'm going to be moving these things into a new project: DamonPayne.AGContrib.  For the sake of my time, this will be a part of the AGT solution for now, until I get time to move it into it's own CodePlex project.

The first denizen of the AGContrib project will be the Input Binding framework as shown above.

I should most likely move some other handy code from the DamonPayne.AG.IoC project into AGContrib as well.  When I get some more time in the coming weeks, I will also be evaluating Unity 1.2 for Silverlight, possibly deprecating my own custom container in favor of it.

 

Conclusion and Next Steps

It's been a while since I've done an AGT article that's entirely design without code.  I'm trying to keep the articles reasonably bite-sized.  I've checked in the most recent design documents, CodePlex change set 10098.  In the next article I'll implement the all the undo functionality.



Monday, January 12, 2009 2:35:07 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, December 11, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Yes, I changed the name of the article.  Here at the 19th step, I decided to ditch the old tagline.

Visual and Code Refactoring

After letting Property Editing sit for too long, I have a list of questions to answer and things I've been meaning to fix or refactor.  I publish these Refactoring articles as part of the Reality Blogging commitment but also in case some of the random code is useful to anyone.  Let's get started.

 

Visual Lasso

I don't know why I had a corner radius on the Visual Lasso, I was probably suffering from some Web2.0itus which I am now over.  I change this and changed the colors:

Vision18

The lasso was also crashable by drawing diagonally until the lasso size would involve negative numbers.  This is fixed.

 

Some Questions

I have gotten some questions from interested parties, which I'll answer here.

  • How about a better constructor for LogMessage?
    • Sure.  More constructors provided
  • Where is IDragDropmanager.RemoveDropTarget?
    • Missing.  I can be very focused trying to get these articles out sometimes.  This has been added.
  • In Page.xaml.cs in the example application, why are you resolving IRegionManager when the Page is the IRegionManager implementation?
    • Force of habit, and I was unsure how I was going to leave that.  And there's nothing wrong with talking to yourself using a Contract...
  • Why are the names inconsistent between IPageView and RootPresenter ?
    • Shameful inconsistency.  IPageView has been renamed to IRootView.
  • Why are the names of the Region Controls in Page.xaml not the same as the Regions themselves?
    • More inconsistency.  They are all named XXXRegion now.  As I looked at this I also wondered why I was using Canvas and not a ContentPresenter, possibly something to do with how much ContentPresenter was chaning in Beta2-->RC0.  At any rate, the regions have good names and I've switched to ContentPresenter.
  • In IRegionManager, what is the difference between RootVisual and TopLevelContainer?  Why do you need both of them?
    • RootVisual is meant so that IRegionManager could provide something to System.Windows.Application.RootVisual, and matches its type of UIElement.  I could probably rename this to ApplicationRootVisual since that is the only reason to have this.  TopLevelContainer is used as the main Playground of services that need to do something visually, like DragDropManager.  This isn't as bad as it first seems, for example the built-in "Popup" class must do something very similar.  Comments have been added.

The Border on DesignSite

When is five minus five not zero?  When you have applied a RenderTransform to a FrameworkElement.  For the border on DesignSite, I would move the control by the border thickness (5px) when I would hide or show the border.  Once you have applied a RenderTransform, though, changing a Canvas.XXXProperty by 5px no longer means 5px.  I fixed this by using a transparent and normal border rather than by changing the border thickness from 0 to 5 to show selection.

 

~Creative Commons

Since I had to choose from a list of licenses on Codeplex (I chose MS-PL) I am removing the creative commons snippets from the code as I see them.

 

Clipping

The Canvas does not clip its children.  This means you can drag controls all over the place outside of the Design surface which is obviously undesirable.

Refactor: I extracted a MouseMoveSelection method and made it virtual so the logic was not totally hidden inside an EventHandler.  This method ultimately calls MoveSelection

I needed to make a decision here, to either create a class that extends Canvas or Panel and does perform some form of clipping on its Children, or to simply implement boundaries within the DesignSurface class.  For now I went with enforcing the bounds in code and snapping the selection back to a valid value.

Floating Properties

I went back and finished implementing my original intention for the PropertyGrid, namely that it would float around with the selection and not be statically docked to the right of the surface.

Refactor: I had a TODO item to un-hack the relationship between IDesigner and DesignSite.  Since IDesigner defines a Surface property of type Canvas this was mostly already done.  DesignSite.DesignParent is now of type IDesigner.

Refactor: Some methods, like GetSelectionBounds(), seemed to belong more on IDesigner than DesignSite after the above change was made.

What I sought to do next was pretty vanilla: if IDesignEditorService.Visual currently had a parent, I would remove it from its parent and add it to IDesigner.Surface or IRegionManager.TopLevelContainer in a location close to the right bounds of the current selection.  Control.Parent and VisualTreeHelper.GetParent both have a return type of DependencyObject.  It seems there is no generic way to remove a FrameworkElement from its visual parent.

DamonPayne.AG.IoC.ControlExtensions  now has a RemoveFromParent() extension method.

The PropertyGrid now floats around to be close to the current selection.

Vision19

 

Bigger Surface

In order to set things up for some future articles, I have change the default size of the DesignSurface and the sample application.  Yes, this means it won't fit on a 1024x768 screen, which apparently some people still have even in this late hour.  We'll fix this in a future article but for now I wanted more room to play.

 

A better Toolbox

The way gestures worked in the toolbox had been bothering me, and I thought I could make it better looking anyway, a little more like Visio perhaps.  I nearly introduced an external dependency on the Silverlight Toolkit, but wanted to see how to do this myself instead.  Given the amount of space I'm working with, I needed to add some more furniture.  I have created an area rug, which I feel really ties the room together.

I created a Control extending Panel, WrapLayoutPanel, to property postion them items in my new and improved toolbox.  The MSDN documentation for MeasureOverride and ArrangeOverride was simple, but surprisingly helpful.

Here's the new and improved toolbox:

Vision20

 

  Conclusion

I've finally gotten around to fixing a number of things that have been bothering me, and I think the application looks a little better too.  I am having a hard time deciding what to do next, and I'm afraid the next two installments are not going to be very sexy, but will be very necessary to tie all the concepts together.

The changes in this article are published as version 0.7.18, Codeplex change set 8710.  While things are still very rough, I did go ahead and make this the default public release on Codeplex.

The live demo has been updated at http://www.damonpayne.com/agt



Thursday, December 11, 2008 6:26:42 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, December 02, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

 

Finishing Property Editing

In the last article, I mentioned the need for some more complex test cases to use to help determine when Property Editing was done.  I could see that too much logic was living in EditServiceHelper and that the editing of properties for multiple items at once was going to become very difficult.  It has been far longer than I intended since the last article (user group presentations, etc.) and there's a lot of cool stuff we can get to after we get Property Editing working the rest of the way so let's get to it.

A Better Example

A much better example was required right off the bat.  This required some more up front thought and setup.  Each Property potentially has a Display Visual and an Edit Visual, and in some cases these may be the same instance.  I need to test some reasonable scenarios:

  1. If multiple items are selected that happen to have a Property with the same name and of the same type and with the same Editors we can edit this Property for all selected items with a single Edit Visual even if the items are not of the same Type.  Only the lowest common denominator of Properties should display.
  2. Basic edit scenarios: an Enum Property is editable in a ComboBox, a string Property is Editable in a TextBox, and so forth.
  3. In some cases the Display Visual will be a custom IDesignablePropertyVisualizer Type which should support some kind of Binding so it auto-updates when edited.
  4. In some cases the Edit Visual will be a custom IDesignablePropertyEditor Type which should support binding as well as setting the value to the actual object on loss of focus or Enter key.
  5. Refactor: It seems clear at this point that since I'm heavily using Bindings, IValueConverter will come in handy, so this has been added to DesignablePropertyDescriptor.

In order to test all of this I'll make the following changes:

  • Couch and Chair will get a Softness property of type Double which I'll edit with a custom slider.  This should work for single or multi selection. (Tests #1, #4)
  • Softness will be displayed with a custom "volume style" Visualizer (Tests #3)
  • The Color property of Chair & Couch will get a Converter that displays a Color name instead of the hex value as shown in the previous article. (Tests #1, #2, #5)

Beyond this, we'll simply need to think about the various "basic" edit scenarios to support, like editing boolean values with a radio button or checkbox.  I've added "Editors" and "Visualizers" namespaces to the DamonPayne.HTLayout project and created the requisite implementations.

 

PropertyGridModel

The various private fields I had been adding to PropertyGrid for keeping track of various states and such clearly needed to be moved to a single class which I now call PropertyGridModel.  All of the methods are virtual to allow enterprising developers to easily tweak behavior.  The public interface for PropertyGridModel :

/// <summary>
/// What are we editing?
/// </summary>
public virtual List<IDesignableControl> Selection { get; set; }
/// <summary>
/// Properties common across the entire Selection
/// </summary>
/// <param name="props"></param>
public virtual void SetProperties(List<DesignablePropertyDescriptor> props)

 

/// <summary>
/// Only 1 property is editing at a time
/// </summary>
public FrameworkElement CurrentEditElement { get; set; }
public virtual void SetDisplayElement(DesignablePropertyDescriptor d, FrameworkElement fe)...
public virtual FrameworkElement GetDisplayElement(DesignablePropertyDescriptor d)...
public virtual List<FrameworkElement> GetAllDisplayElements()...
public virtual void SetEditElement(DesignablePropertyDescriptor d, FrameworkElement fe) ...
public virtual FrameworkElement GetEditElement(DesignablePropertyDescriptor d)...
public virtual DesignablePropertyDescriptor GetDescriptorForEditElement(FrameworkElement fe)...
public virtual DesignablePropertyDescriptor GetDescriptorForDisplayElement(FrameworkElement fe)...
/// <summary>
/// Remove everything from the Model
/// </summary>
public virtual void Reset()...

 

EditServiceHelper

I continued by overhauling the EditServiceHelper class.  I realized my notion of the TypeDescriptor-like functionality of this class was not fully baked, but sitting down to look at it the second time a much more cohesive purpose coalesced.  I also made sure to pull in the concepts of IDesignablePropertyEditor and IDesignablePropertyVisualizer right away.  I'm only going to show the Display path and no the Edit path here for brevity, they are very similar.

In a static constructor we set up some defaults, this will be expanding as I go.

AddDefaultDisplayor(typeof(string), typeof(TextBlock));
AddDefaultDisplayor(typeof(Color), typeof(TextBlock));
AddDefaultEditor(typeof(string), typeof(TextBox));
AddDefaultEditor(typeof(Color), typeof(ComboBox));
AddBasicBindableDisplayType(typeof(TextBlock), TextBlock.TextProperty);
AddBasicBindableEditType(typeof(TextBox), TextBox.TextProperty);
AddBasicBindableEditType(typeof(ComboBox), ComboBox.SelectedItemProperty);

These are all public static methods in case someone needs to expand this faster than I get to it.

Client code (PropertyGrid) will call GetDisplayInstance to get some type of Visual that can be used to represent the value of a single property

public static FrameworkElement GetDisplayInstance(IDesignableControl instance, DesignablePropertyDescriptor desc)
{
    //if null we try to find a default, otherwise see if we can do a binding anyway using the override
    if (null == desc.DisplayType || _basicBindableDisplayTypes.ContainsKey(desc.DisplayType))
    {
        Type displayType = _displayors[desc.PropertyInfo.PropertyType];
        FrameworkElement displayInstance = null;
        if (null != displayType)
        {
            displayInstance = (FrameworkElement)Activator.CreateInstance(displayType);
            SetupDisplayInstanceBinding(instance, desc, displayInstance);
        }
        return displayInstance;
    }
    else if (desc.DisplayType.ImplementsInterface(typeof(IDesignablePropertyVisualizer)))
    {
        var visualizer = (IDesignablePropertyVisualizer)Activator.CreateInstance(desc.DisplayType);
        visualizer.Initialize(instance, desc);
        return visualizer.Visual;
    }
    return null;
}

First check defaults, then check special overrides, then ultimately give up.  ImplementsInterface is an extension method in the DamonPayne.AGT.IoC project.  SetupDisplayInstanceBinding handles the rest of the work which is fairly simple with the help of Silverlight Binding.

protected static void SetupDisplayInstanceBinding(IDesignableControl instance, 
    DesignablePropertyDescriptor desc, FrameworkElement display)
{
    if (_basicBindableDisplayTypes.ContainsKey(display.GetType()))
    {                
        var dProp = _basicBindableDisplayTypes[display.GetType()];
        Binding b = new Binding(desc.PropertyInfo.Name);
        b.Converter = desc.Converter;
        b.Mode = BindingMode.TwoWay;
        b.Source = instance;
        display.SetBinding(dProp, b);
    }
}

How might a custom Property Visualizer work?  Take a look at part of the code behind for displaying the "softness" property of Couches & Chairs:

public double Softness
{
    get { return (double)GetValue(SoftnessProperty); }
    set { SetValue(SoftnessProperty, value); }
}

// Using a DependencyProperty as the backing store for Softness.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty SoftnessProperty =
    DependencyProperty.Register("Softness", typeof(double), typeof(SoftnessVisualizer), new PropertyMetadata(SoftnessChanged));

public static void SoftnessChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    if(obj is SoftnessVisualizer)
    {
        ((SoftnessVisualizer)obj).ScaleSoftness();
    }
}

protected void ScaleSoftness()
{
    if (Softness > 0.0)
    {
        VisualScale.ScaleX = Softness;
        VisualTranslate.X = 10 * Softness;
    }
    else
    {
        VisualScale.ScaleX = 1.0;
        VisualTranslate.X = 0.0;
    }
}

/// <summary>
/// We know we're just for softness!
/// </summary>
/// <param name="instance"></param>
/// <param name="desc"></param>
public void Initialize(DamonPayne.AGT.Design.IDesignableControl instance, DamonPayne.AGT.Design.Types.DesignablePropertyDescriptor desc)
{
    if (null != instance)
    {
        Binding b = new Binding("Softness");
        b.Converter = desc.Converter;
        b.Mode = BindingMode.TwoWay;
        b.Source = instance;
        SetBinding(SoftnessVisualizer.SoftnessProperty, b);
    }
}

The visual representation of softness here is a triangle that I am stretching based on Softness but that's not important.  In Initialize we set up a binding to the particular Property we care about which handles keeping in sync with the underlying object.  Using a changed callback for the Softness DependencyProperty allows us to tweak the UI if an editor changes this value in some fashion.

You can see here that I am making a heavy dependence on System.Windows.Data.Binding concepts which in turn means DependencyProperties.  This is OK as far as I'm concerned.  The Binding in Silverlight/WPF is the Data Binding you've always wished you had.  It is awesome.  It is likely going to be used frequently and you should learn it, love it, learn where it breaks down, and return to loving it.

 

The PropertyGrid logic is now fairly simple and just swaps an Edit Visual out for a Display Visual when the Display Visual is clicked on.

 

The ColorConverter I wrote may be helpful as well...

public class ColorConverter : IValueConverter
{

    static ColorConverter()
    {
        _colorNameToColor = new Dictionary<string, Color>();
        _colorToName = new Dictionary<Color, string>();
        Type cType = typeof(System.Windows.Media.Colors);
        PropertyInfo[] colors = cType.GetProperties(BindingFlags.Public | BindingFlags.Static);
        foreach (var propInfo in colors)
        {
            var c = (Color)propInfo.GetValue(null,null);
            _colorNameToColor.Add(propInfo.Name, c);
            _colorToName.Add(c, propInfo.Name);
        }
    }

    private static Dictionary<string, Color> _colorNameToColor;
    private static Dictionary<Color, string> _colorToName;


    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is Color)
        {
            Color src = (Color)value;
            if (targetType == typeof(string))
            {
                if (_colorToName.ContainsKey(src))
                {
                    return _colorToName[src];
                }
                else
                {
                    return src.ToString();
                }
            }
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is string)
        {
            string src = value.ToString();
            if (targetType == typeof(Color))
            {
                if (_colorNameToColor.ContainsKey(src))
                {
                    return _colorNameToColor[src];
                }
            }
        }

        return null;
    }
}

How does it look?

I needed to create some better visuals than the placeholders I had at the end of the previous article.  The default ControlTemplate for PropertyGrid now looks like this with a Chair selected.  Click on any image for the larger version.

Vision14

Note my special visualizer (I am no artist) for Softness.  When I select Softness, I get a custom Editor as well:

 Vision15

With a chair, a couch, and a Dummy Button selected, the only Property they have in common is Name, so only name shows up in the grid:

Vision16

Couches and Chairs have lots in common, so I could edit the Color of them all at once:

Vision17

 

Unit Tests

Jeff Wilcox released a full Silverlight 2 version of his Silverlight Unit Test Framework, so the AGT Solution has been updated to use this.  I have yet to find new Templates, so the Templates still say Beta and the default test project has to be tweaked slightly.  This is extremely handy for things like IValueConverters, and I will be greatly increasing test coverage in the future.

Conclusion

So, we've got Property Editing working now and this is starting to look like a real Design Time Environment.

The source code is checked into Codeplex as downloadable Change Set 8353 here.  I have also created a 0.7.17.2 "Planning" source drop on Codeplex.

 

The Live Demo has been updated at http://www.damonpayne.com/agt/

 

In the next article, we will be going through some refactoring items and some questions that I've been meaning to get to.



Tuesday, December 02, 2008 3:57:51 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, November 21, 2008

Regular readers may observe that my interest in Silverlight is primarily in making business applications and Visual Tools. I am not an artist and I don't stream music or movies.  No, I'd just like to see Silverlight replace HTML, CSS, and Javascript.  There are a few issues with this plan right now (other than wish thinking) - binding ought to be closer to what WPF has.  There are some handy controls missing. 

There's no built in Validation strategy. 

Obviously nothing stops me from doing validation in a completely manual fashion but it's unlike Microsoft to leave holes like this...

Strategy

We have Extension Methods, but not Extension Properties or Extension Events, so simply adding Validating event handlers isn't an option.  What's more, the typical Windows Forms strategy requires an Extender Provider framework - perhaps when I get further on the AGT Project I'll revisit this, but for now something quicker to implement would be better.

For some reason the ASP.Net model was intriguing to me given the current state of Silverlight.

  1. The Validators have a visual representation and function essentially as a Control.
  2. The Validators "point to" the Control they will validate, so they are completely outside the rest of the functionality on the Page so to speak.
  3. Making sure to trigger Validation via code like if(Page.IsValid) { /* do something*/} is a fair enough way to write code.

So, could we create something like this, but in a reasonably Silverlight-y way? Read on.

Test Form and three sample validation scenarios

I have created a very simple Wine Order Form:

Form0

I have some simple data requirements for this order form.

  • For Name, I'd like something similar to the Asp.Net RequiredFieldValidator
  • For Email, I'd like a RegexValidator
  • For Bottles of Wine I'd like a RangeValidator

Design Goals

So, how would I like this to work and what should the programming experience be?

  • I'd like some sort of Control in the Visual Tree representing the Validation state of an associated Control; it should be easy to Template
  • I do not want to require any interface implementation, base classes, or any changes to the Visual Tree besides the addition of the Validation visuals. (ie no <v:ValidationArea>... your XAML here </v:ValidationArea>, although this is a common enough model in Silverlight and WPF)
  • Calling an arbitrary # of Validators on any given Control or Panel should require as little code as possible
  • Adding new Validator types should be as easy as possible.
  • It should feel like the Validators have saved programming time and created consistency versus pure manual validation.

 

Implementation

How did I do on these goals?  Let's see.

Validator Control Class

As I stated, I've taken the approach of creating a Control which will live in the Silverlight Visual Tree.   Any inheritance involving XAML & User Controls is painful or impossible, but I wanted to see about directly inheriting from Control and using a ControlTemplate instead of working at any kind of visual inheritance.  I'm happy with the results.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace DamonPayne.AGContrib.Validation
{
    [TemplatePart(Name = "LayoutRoot", Type = typeof(Panel))]
    public class Validator : Control
    {
        public Validator()
        {
            DefaultStyleKey = typeof(Validator);
            Loaded += new RoutedEventHandler(Validator_Loaded);
        }

        private Panel _layoutRoot;

        void Validator_Loaded(object sender, RoutedEventArgs e)
        {
            CheckValidState(this);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _layoutRoot = (Panel)GetTemplateChild("LayoutRoot");
        }

        /// <summary>
        /// A single Framework Element to display when Valid, perhaps an empty TextBlock?
        /// </summary>
        public FrameworkElement ValidContent
        {
            get { return (FrameworkElement)GetValue(ValidContentProperty); }
            set { SetValue(ValidContentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ValidContent.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValidContentProperty =
            DependencyProperty.Register("ValidContent", typeof(FrameworkElement), typeof(Validator), new PropertyMetadata(new TextBlock()));



        public FrameworkElement InValidContent
        {
            get { return (FrameworkElement)GetValue(InValidContentProperty); }
            set { SetValue(InValidContentProperty, value); }
        }

        //Inheritance, does NOT like sharing visual elements, very sneaky
        public static readonly DependencyProperty InValidContentProperty =
            DependencyProperty.Register("InValidContent", typeof(FrameworkElement), 
            typeof(Validator), 
            new PropertyMetadata(new TextBlock { Text="*", Foreground=new SolidColorBrush(Colors.Red) }));



        /// <summary>
        /// Tool tip content, possibly explaining more information about why the value is invalid
        /// </summary>
        public FrameworkElement InvalidToolTip
        {
            get { return (FrameworkElement)GetValue(InvalidToolTipProperty); }
            set { SetValue(InvalidToolTipProperty, value); }
        }

        // Using a DependencyProperty as the backing store for InvalidToolTip.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InvalidToolTipProperty =
            DependencyProperty.Register("InvalidToolTip", typeof(FrameworkElement), typeof(Validator), new PropertyMetadata(null));


        /// <summary>
        /// Is the target Control currently valid
        /// </summary>
        public bool IsValid
        {
            get { return (bool)GetValue(IsValidProperty); }
            set { SetValue(IsValidProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsValid.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsValidProperty =
            DependencyProperty.Register("IsValid", typeof(bool), typeof(Validator), new PropertyMetadata(true, IsValidChanged));


        public static void IsValidChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            if (obj is Validator)
            {
                var v = (Validator)obj;
                CheckValidState(v);
            }
        }

        /// <summary>
        /// show/hide the valid/invalid FrameworkElement
        /// </summary>
        /// <param name="v"></param>
        private static void CheckValidState(Validator v)
        {
            if (null != v.ValidContent && null != v.InValidContent)
            {
                if (v.IsValid)
                {
                    v.ValidContent.Visibility = Visibility.Visible;
                    v.InValidContent.Visibility = Visibility.Collapsed;
                }
                else
                {
                    v.ValidContent.Visibility = Visibility.Collapsed;
                    v.InValidContent.Visibility = Visibility.Visible;
                }
            }
        }

        /// <summary>
        /// The name of the Control within the visual tree we should try to validate
        /// </summary>
        public string ControlToValidate
        {
            get { return (string)GetValue(ControlToValidateProperty); }
            set { SetValue(ControlToValidateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ControlToValidate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ControlToValidateProperty =
            DependencyProperty.Register("ControlToValidate", typeof(string), typeof(Validator), new PropertyMetadata(null));


        /// <summary>
        /// When overridden in a derrived class, checks for a valid value
        /// in <paramref name="ctv"/>
        /// </summary>
        /// <param name="ctv"></param>
        /// <returns></returns>
        public virtual bool Validate(FrameworkElement ctv)
        {
            return true;
        }

        /// <summary>
        /// Helper method for derived classes
        /// </summary>
        /// <param name="fe"></param>
        /// <returns></returns>
        protected virtual string GetInputValue(FrameworkElement fe)
        {
            string val = string.Empty;
            if (fe is TextBox)
            {
                val = ((TextBox)fe).Text;
            } //else if ComboBox, etc.
            return val;
        }
    }
}

We define three dependency properties for showing content, presumably using a ContentPresenter in the default template for Validator.  ValidContent, InValidContent, and InvalidToolTip.  We leave the Validate function empty, and the work of showing or hiding the correct content happens in CheckValidState.

Default Validator ControlTemplate

We target Validator with this ControlTemplate:

<ControlTemplate TargetType="local:Validator">
    <Canvas x:Name="LayoutRoot">
        <ContentPresenter x:Name="ValidPresenter" Content="{TemplateBinding ValidContent}"></ContentPresenter>
        <ContentPresenter x:Name="InValidPresenter" Content="{TemplateBinding InValidContent}">
            <ToolTipService.ToolTip>
                <ContentPresenter x:Name="InvalidToolTipPresenter" Content="{TemplateBinding InvalidToolTip}"></ContentPresenter>
            </ToolTipService.ToolTip>
        </ContentPresenter>
    </Canvas>
</ControlTemplate>

This should be easy to understand.   Since this is an early experiment I haven't created any Visual States yet.

 

Validator Implementations

Surprisingly, creating classes that extend Validator worked out fairly well.  We can review the main pitfall in the ValidContentProperty Dependency Property registration.  Note the default value inside the PropertyMetadata constructor.  I left this in to make a point - only one instance of this TextBlock will be created, and a single Control cannot appear multiple times in the Visual Tree.  Be sure to provide values in each instance or you will get hard to grok errors.  For the sake of brevity, we can just review the implementation for RegexValidator:

using System.Text.RegularExpressions;
using System.Windows;

namespace DamonPayne.AGContrib.Validation
{
    public class RegexValidator  : Validator
    {
        public RegexValidator()
        {
            DefaultStyleKey = typeof(Validator);
        }

        public string RegularExpression
        {
            get { return (string)GetValue(RegularExpressionProperty); }
            set { SetValue(RegularExpressionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RegularExpression.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RegularExpressionProperty =
            DependencyProperty.Register("RegularExpression", typeof(string), typeof(RegexValidator), new PropertyMetadata(string.Empty));

        public override bool Validate(FrameworkElement ctv)
        {
            if (!string.IsNullOrEmpty(RegularExpression))
            {
                Regex r = new Regex(RegularExpression);
                string text = GetInputValue(ctv);

                return r.IsMatch(text);
            }
            return true;
        }
    }
}

There are a couple of things to note here.  Because this class is simply adding some logic we use DefaultStyleKey = typeof(Validator); in the constructor.  We could conceivably want different Validators to have utterly different visual representations, but in those cases we can create a ControlTemplate for those instances only.  Surprisingly this works just fine.  We've defined a RegularExpression property we can set from XAML and overridden Validate to do the Regex check.

Adding the Validators in XAML

Given all of this, it's easy to add the Validators onto my order form:

<!-- Name Row-->
<TextBlock Grid.Row="1">Name:</TextBlock>
<TextBox x:Name="NameTxt" Grid.Row="1" Grid.Column="1" Height="25" VerticalAlignment="Top"></TextBox>
<v:RequiredFieldValidator x:Name="NameReq" ControlToValidate="NameTxt" Grid.Column="2" IsValid="True">                
</v:RequiredFieldValidator>            

Obviously, the value of ControlToValidate must be a valid Name somewhere in the visual tree.  Because we allow the display of anything for valid vs. invalid Controls, and we can set the initial valid state my order form now looks like this when first loaded, calling out the fact that Wine Bottles needs a real value:

Form1

Firing the Validators

Given the primitive state of the example application so far, a single extension method for type FrameworkElement will cause all of the validators contained within that FrameworkElement to do their thing.  The extension code is worth taking a quick look at.

namespace DamonPayne.AGContrib.Validation
{
    public static class FrameworkElementExtensions
    {
        /// <summary>
        /// Search the control's Visual Tree for Validators, and run them!
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static bool IsValid(this FrameworkElement c)
        {
            bool valid = true;
            var lv = FindAllValidators(c);

            foreach (var v in lv)
            {
                var ctv = (Control)c.FindName(v.ControlToValidate);
                if (null != ctv)
                {
                    if (!v.Validate(ctv))
                    {
                        valid = false;
                        v.IsValid = false;
                    }
                    else
                    {
                        v.IsValid = true;
                    }
                }
            }

            return valid;
        }

        public static List<Validator> FindAllValidators(FrameworkElement fe)
        {
            return FindAllValidators(fe, new List<Validator>());
        }

        public static List<Validator> FindAllValidators(FrameworkElement fe, List<Validator> lst)
        {
            int count = VisualTreeHelper.GetChildrenCount(fe);
            for (int i = 0; i < count; ++i)
            {
                DependencyObject d = VisualTreeHelper.GetChild(fe, i);
                if (d is Validator)
                {
                    lst.Add((Validator)d);
                }
                if (d is FrameworkElement)
                {
                    FindAllValidators((FrameworkElement)d, lst);
                }
            }
            return lst;
        }

    }    
}

You may note that only certain elements such as Canvas define a "Children" property.  VisualTreeHelper is the only way I know of to walk the Visual Tree in a generic fashion.  This allows us to look for Validators within the target FrameworkElement no matter how nested.  I will revisit my choice of FrameworkElement as the entry point.  With this Extension Method, validating my form when I attempt to submit is easy, "Form" being the name of my top level Grid.

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (Form.IsValid())
    {
        //Do something meaninful
    }
}

So, if we push the Submit button without doing anything, we see this ...

Form2

... but providing valid values ...

Form3

 

Conclusion

So, what do you think?  Is this worth a little more work?  I would probably add some kind of Validation Summary, some Visual States to Validator, potentially support Validation Groups, and add a way to dynamically fire the Validators when a Control loses focus.

Send me a note with your comments.

Source code:

DamonPayne.AGContrib.zip (44.75 KB)


Friday, November 21, 2008 11:03:43 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, November 19, 2008

The talk went very well last night and I got very positive feedback.  Thanks to John from Microsoft for helping with the Projector system, which mysteriously shut down at special pre-programmed times twice during the night; this was a complex topic and the audience was excellent.

Now that I'm done preparing for this, you can expect the next AGT article to happen soon.

Here are the slides and code from the talk:

AGSIGControlTeplatePreso.zip (1.03 MB)


Wednesday, November 19, 2008 12:06:31 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, November 18, 2008

http://www.wi-ineta.org/DesktopDefault.aspx?tabid=192

Hopefully I will see some of you there at 6pm in the Microsoft offices.  I think I'll be visiting the bar at Thunder Bay Grill next door after the show...



Tuesday, November 18, 2008 11:27:16 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, November 10, 2008

I will be speaking next week at the Silverlight Special Interest Group, a subset of the Wisconsin .NET user's group.  The topic is Control Templating, Styling, and the Visual State Manager.  For more details check out:

http://www.wi-ineta.org/DesktopDefault.aspx?tabid=192

 

 



Monday, November 10, 2008 10:46:45 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 06, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Yes, I've switched to Live Writer full time now.  The VSPaste plug-in is excellent.

Editing Properties

The theory is baked and the anticipation is high, it’s time to edit Properties inside the designer. I add the DesignablePropertyDescriptor type to the solution and add the GetDesignProperties method to the IDesignableControl interface. With this added I need to go about providing implementations. This project is going to start and end with the purple Couch.

public Color FillColor { get; set; }

        public List<DesignablePropertyDescriptor> GetDesignProperties()
        {
            return new List<DesignablePropertyDescriptor>();
        }

I need to implement this for the FillColor property.

public List<DesignablePropertyDescriptor> GetDesignProperties()
      {
          List<DesignablePropertyDescriptor> props = new List<DesignablePropertyDescriptor>();
          
          DesignablePropertyDescriptor fillColor = new DesignablePropertyDescriptor();
          fillColor.PropertyInfo = GetType().GetProperty("FillColor");
          fillColor.DisplayName = "Color";
          fillColor.DisplayType = typeof(TextBlock);
          fillColor.Editable = true;
          fillColor.EditorType = typeof(ComboBox); 
          fillColor.SupportsStandardValues = true;
          fillColor.StandardValues = new List<object>( new object[] {Colors.Purple, Colors.Red, Colors.Gray, Colors.Brown, Colors.Gray});
            return props;            
        }

I’m already questioning the decision not to use attributes, that’s a lot of code for one property. Still, I’ll follow this through for now. Later I’ll dig up some WinForms designer code for comparison. Now I need to provide my default implementation for IDesignableControlInspector.

    public interface IDesignableControlInspector : IService
    {
        List<DesignablePropertyDescriptor> Inspect(IDesignableControl idt);
    }
    public class DefaultInspector : IDesignableControlInspector
    {
        public System.Collections.Generic.List<DesignablePropertyDescriptor> Inspect(IDesignableControl idt)
        {
            if (null != idt)
            {
                return idt.GetDesignProperties();
            }
            return null;
        }
    }

Refactor: At this point, I can see that my IService interface is broken. I’m forcing myself to implement Startup() and Shutdown() methods that I have yet to use in any meaningful way. Removing Startup from the IService definition gives a single compiler error from ServiceManager. The methods are gone until I need them. Of course, this leaves IService as a simple “marker” interface with no methods. Not terribly evil, but there are better ways to supply what is essentially metadata in .NET.

Now I create the IDesignEditorService interface:

public interface IDesignEditorService:IService
{
    Control Visual { get; }
    void Edit(IList<IDesignableControl> targets);
}

For now, I will leave IDesignablePropertyEditor alone.  I need to create a PropertyGrid control and wire up the code needed to use it.  The specifics of making the templatable PropertyGrid will be in the next article.  The PropertyGrid must implement IDesignEditorService.

public Control Visual
{
    get
    {
        return this;
    }
}

public void Edit(IList<IDesignableControl> targets)
{
    //TODO: something
}

Now, in order to begin doing our work of displaying and editing properties, we need to get whatever IDesignableControlInspector has been registered.

public PropertyGrid()
{
    DefaultStyleKey = typeof(PropertyGrid);
    Inspector = ServiceManager.Resolve<IDesignableControlInspector>();
}

IDesignableControlInspector Inspector { get; set; }

And now we can begin doing some work inside Edit. 

public virtual void Edit(IList<IDesignableControl> targets)
{
    if (null != targets && targets.Count > 0 && null != targets[0])
    {
        if (targets.Count > 1)
        {
            EditMultiple(targets);
        }
        else
        {
            EditSingle(targets[0]);
        }
    }
    else
    {
        ClearProperties();
    }
}

I've decided it really would be nice to handle editing multiple items with the same Properties, so we'll do that too.  In order to keep methods small and readable and provide some extra support for alternative implementations of IDesignEditorService I have created EditServiceHelper to assist with the various reflection and control instantiation operations.  In order to more easily see how well this is working, I start by wiring up Selection events with the PropertyGrid.  This means that my DesignSurface control now needs to get an IDesignEditorService injected and we need to handle selection events.

private ISelectionService _selectionSvc;

public ISelectionService SelectionSvc 
{
    get
    {
        return _selectionSvc;
    }
    set
    {
        if (null != _selectionSvc)
        {
            _selectionSvc.SelectionChanged -= new EventHandler(SelectionSvc_SelectionChanged);
        }
        _selectionSvc = value;
        _selectionSvc.SelectionChanged += new EventHandler(SelectionSvc_SelectionChanged);
    }
}
void SelectionSvc_SelectionChanged(object sender, EventArgs e)
{
    List<IDesignableControl> idtList = new List<IDesignableControl>();
    foreach (var idt in SelectionSvc.GetSelection())
    {
        if (idt is DesignSite)
        {
            idtList.Add(((DesignSite)idt).HostedContent);
        }
        else
        {
            idtList.Add(idt);
        }
    }
    EditSvc.Edit(idtList);    
}      

Ok, nothing crazy so far, then things got interesting.  How to generically have some kind of binding between "some visual representation of a property" and "some property on an IDesignableControl" ?  I went back and added another property to my Couch, namely the "DesignTimeName", in order to illustrate this better.  This is where things stand now inside Couch.GetDesignProperties()

public List<DesignablePropertyDescriptor> GetDesignProperties()
{
    List<DesignablePropertyDescriptor> props = new List<DesignablePropertyDescriptor>();

    DesignablePropertyDescriptor name = new DesignablePropertyDescriptor();
    name.PropertyInfo = GetType().GetProperty("DesignTimeName");
    name.DisplayName = "Name";
    name.Editable = true;
                
    DesignablePropertyDescriptor fillColor = new DesignablePropertyDescriptor();
    fillColor.PropertyInfo = GetType().GetProperty("FillColor");
    fillColor.DisplayName = "Color";
    fillColor.DisplayType = typeof(TextBlock);
    fillColor.Editable = true;
    fillColor.EditorType = typeof(ComboBox); 
    fillColor.SupportsStandardValues = true;
    fillColor.StandardValues = new List<object>( new object[] {Colors.Purple, Colors.Red, Colors.Gray, Colors.Brown, Colors.Gray});

    props.Add(name);
    props.Add(fillColor);

    return props;            
}

Inside PropertyGrid.EditSingle, we build up our Grid rows & columns using the EditServiceHelper I mentioned earlier.

protected virtual void EditSingle(IDesignableControl idt)
{
    List<DesignablePropertyDescriptor> props = Inspector.Inspect(idt);
    var propCount = 0;
    foreach (var descriptor in props)
    {
        _propertyPart.RowDefinitions.Add(new RowDefinition());
        TextBlock tb = new TextBlock();
        tb.Text = descriptor.DisplayName;                
        tb.SetValue(Grid.RowProperty, propCount);
        tb.SetValue(Grid.ColumnProperty, 0);
        //
        FrameworkElement displayElement = EditServiceHelper.GetBoundDisplayElement(descriptor, idt);
        displayElement.SetValue(Grid.RowProperty, propCount);
        displayElement.SetValue(Grid.ColumnProperty, 1);
        displayElement.GotFocus += new RoutedEventHandler(displayElement_GotFocus);
        //
        _propertyPart.Children.Add(tb);
        _propertyPart.Children.Add(displayElement);
        ++propCount;
    }
}

That's not too bad so far.  Here's a screenshot with my so far, so lame PropertyGrid template.

Vision12

I'm going to skip over the implementations inside EditServiceHelper for now, it's in the code if you're curious.  Suffice to say it contains some Property to Control mappings for some basic supported types.  For example, a Property of Type string will be both displayed and edited using a TextBox element and a Two Way Binding. When we get into more complex Visualization and Edit scenarios in a later article.

The next thing we need to do is handle a couple of simple edit scenarios when the display element gets focus, as shown above in EditSingle.

void displayElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    VerifyEditVisualization(sender);   
}

void displayElement_GotFocus(object sender, RoutedEventArgs e)
{
    VerifyEditVisualization(sender);            
}

private void VerifyEditVisualization(object sender)
{
    if (null != _targets && _targets.Count > 0)
    {
        FrameworkElement element = (FrameworkElement)sender;
        Type t = sender.GetType();
        DesignablePropertyDescriptor descriptor = _descriptorMap[element];
        Type editType = EditServiceHelper.GetEditElementType(descriptor);
        if (!t.Equals(editType))
        {
            FrameworkElement editElement = EditServiceHelper.GetBoundEditElement(descriptor, editType, _targets[0]);
            editElement.SetValue(Grid.RowProperty, element.GetValue<int>(Grid.RowProperty) );
            editElement.SetValue(Grid.ColumnProperty, 1);
            _propertyPart.Children.Add(editElement);
            _editElement = editElement;
        }
        //else do nothing, the Editor is the same as the Displayor
    }
}

One thing you can see immediately is that my colors are listed using their Hex #s, so I need to introduce the value converters into the mix.  I also need to fill in a better look and feel for the PropertyGrid, handle Multiple IDC Edit,  and invent a scenario where I can test out the IDesignablePropertyEditor idioms.  This article is already getting a bit long, so I will do some more cleanup and stop here for now.

Making Property Registration Easier

I'm still thinking that writing code for this property edit scheme this will be easier than the current WinForms equivalent, but I realized immediately that it could be better.  I have created a couple of new methods in EditServiceHelper:

/// <summary>
/// Returns common props from IDesignableControl : DesignTimeName, 
/// </summary>
/// <returns></returns>
public static List<DesignablePropertyDescriptor> GetDefaultDescriptors()
 
/// <summary>
/// Return default <code>DesignablePropertyDescriptor</code> objects for each Property name
/// </summary>
/// <param name="names"></param>
/// <returns></returns>
public static List<DesignablePropertyDescriptor> GetDescriptors(IEnumerable<string> names, IDesignableControl idc)

The default can be merged with any custom list a control author wishes to return.

 

Updating the Existing Controls

Refactor: The Couch, Chair, Center channel speaker, and Tower speaker controls were all refactored to use the new convienience methods to return their own properties.  The descriptions no longer say "red chair" or "purple" couch, since we can actually edit the properties of items on the surface now!

Here's what the application looks like now:

Vision13

Yes, we left Property Editing half done in order to keep each article shorter.

 

Conclusion

If you're following the source code, there were several tiny refactorings made that weren't mentioned here.  Speaking of code, as I previously blogged, the project is in CodePlex now at http://www.codeplex.com/agt. The current source code for this article, then, is the 0.7.16.1 Release.  Tune in next time to see Property Editing reach a more finished state.

The live demo has been updated at http://www.damonpayne.com/agt



Thursday, November 06, 2008 5:20:51 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

The various source drops were taking up a lot of space on my server and I promised to open source this tool, and now it's done.  The AGT project has moved to Codeplex.

http://www.codeplex.com/agt

I have not published an actual Release yet, but from this point forward I'll be tagging a release at the end of each article.  Parts [16] and [17] are in progress now.



Thursday, November 06, 2008 10:14:17 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, October 30, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Choosing an Approach to Editing Properties

One of the last top level pieces to begin fleshing out is Property Editing.  I don’t want to see “Red Couch” in the toolbox anymore: I want to see “Couch” and to change its color at runtime by editing his properties.  Having had a lot of experience writing things like this so as to fit neatly within the framework Microsoft gives us, I felt very familiar with the benefits and drawbacks of these approaches.  I had to ask myself some questions:

1.       Is the PropertyGrid really the best way to go about changing attributes of objects on a design surface?

2.       Is a Visual Studio style grid the best route?  Maybe a smaller gird that appears right next to a Component (ala Visio) is better?  Maybe there should be more interaction with the Component itself?

3.       How important is it to support the editing of a Property for many Components at once?

4.       How important is Undo?  Redo?

5.       What is the best contract between IDesignableControl and “the design time environment” for determining which properties are editable and how they should be edited?

When writing custom controls for the Visual Studio designer, it always bothered me that the Contract between my Controls and the Designer Time Environment was simply some attributes on public properties.  Now that I’m in a position to change it for my own world, I’m having trouble thinking of something better.  My ideas on what is the most “correct” in terms of Object- and Component- oriented semantics is not the only thing at play here.  As a component creator, what do I want my software development experience to like?  Is placing eight attributes on a property the easiest and most sensible way?  If I diverge from what’s present in the Visual Studio design time environment, how much extra work am I creating?

What design-time support is present in Silverlight anyway?

Designer Support native to Silverlight

What namespaces, classes, interfaces, and attributes we are accustomed to from “full framework” design time support have made it into Silverlight?

System.Web.UI.Design.SilverlightControls

This namespace only contains things related to a Silverlight plug-in control on ASPX pages.  There’s nothing useful for us here.

System.ComponentModel

Many of the familiar friends are here:

·         CategoryAttribute – Place this on a property indicating what category the property belongs to in a categorized PropertyGrid.

·         DefaultValueAttribute – specify the default value for a property

·         DescriptionAttribute- a Description for a property or event

·         DesignerProperties class.  This one is interesting.  At the time I started this article, RTW was not quite out and the documentation on MSDN didn’t really say anything about what this actually did.  The description now says “The DesignerProperties class provides attached properties that can be used to query the state of a control when it is running in a designer. Designer tools will set values for properties on objects that are running in the designer.” Ultimately, though, this is an attached property for “IsInDesignMode”, which I don’t know if I’ll need or not.

·         EditorBrowsableAttribute – In what situations should this property be shown by designers or intellisense

·         TypeConverter – TypeConverter is missing some things from the full framework. The MSDN documentation still says it supports “standard values” but those methods (to return a standard values collection) are missing in Silverlight.

·         TypeConverterAttribute –present and accounted for!

Missing in action:

·         System.ComponentModel.TypeDescriptor – In the full framework, TypeDescriptor is extremely important to the design-time environment.  TypeDescriptor is used to augment Reflection to specify what attributes a Component has. 

o   TypeDescriptor tells us what kind of Editor is used to modify an instance of a Component

o   TypeDescriptor tells us what kind of Designer a particular component uses

o   TypeDescriptor is used to create design-time instances of a type

·         TypeDescriptor is extensible via IExtenderProvider, ITypeDescriptorFilterService, ICustomTypeDescriptor, all missing.

·         System.ComponentModel.Editor

·         System.Drawing.UITypeEditor

In some cases I’ve already made design decisions that negate the need for some of these missing things.  Other’s I’ll have to introduce or replace.

Design Goals

Property editing is complex.  Now that I see the lay of the land, I can state some design goals and some approaches to achieving them.

1.       The items on the design surface (IDesignableControl) need to be able to be inspected for a list of Properties that are displayable and editable.  It should be painless for Control authors to do this.

2.       When a property is found to be displayable, we must be able to determine what type of visual Control should be used to display the property value.

3.       When a property is found to be editable, we must be able to determine:

a.       The type of the property

b.      The category of the property

c.       What type of visual Control should be used to edit the property value

4.       We should be able to display all of this in a PropertyGrid-esque fashion.

In order to reach these goals, I decide on the following:

1.       I’m going to try replacing the attribute based Component-Designer contract mechanism with new and modified interfaces.

2.       I’m going to make the Component inspection mechanism pluggable, in case someone really wants to fall back on Reflection.

3.       I’m going to come up with some better named interfaces and types to use to modify property values.

4.       I’m going to build some helpers/extension methods to make this painless for IDesignableControl authors.

5.       I’m going to build a PropertyGrid from scratch.

Working on these ideas, I have come up with this:

Since no code was written as part of this article, the most updated code is still AGT[14].

In the next article we’ll look into implementing this approach.



Thursday, October 30, 2008 1:40:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, October 21, 2008

When one is giving a technical presentation, issues around source code can be some of the more difficult to plan for.  Do you have the code done already?  Do you write the code on the spot?  If you write code on the spot do you have the code divided into various snippets you can instantly drop in, or do you really type everything?  Is it OK to use a tool like CodeRush or ReSharper that not everyone will be familiar with?  Do you need to be prepared to offer code in both C# and VB.Net?

There has been a "current" or "meme" going around the local community here regarding how the code used in demonstrations is structured.  Some people, it seems, are tired of seeing Database Driven examples or One-Tier samples for .NET topics.  Most commonly picked on is LINQ-to-X: I have heard multiple complaints that it is bad form to bust out "var query = from x in context select x;" from an ASP.Net code behind to show how LINQ works.  In a real application one would have data access classes, Presenters or Controllers, possibly extra business logic classes, and so forth.  The argument goes on that giving a talk and failing to use appropriate separation of concerns like this teaches bad habits to developers and makes the members of the .NET community look like we all implement the Simpleton Pattern.

David Palfery vented to me that after his recent User Group talk on some Silverlight concepts someone approached his boss and gave a reproach for not using more a appropriate separation of concerns in his code demos.  What's the deal with that?  If you can't raise your hand to ask about this, talk to the presenter after the show, or comment on their blog - you are a coward.  Whatever your lot in life, it seems to me to be the most basic of courtesies to extend to someone who's taken their time to hopefully help you grok something.  But, leaving etiquette aside, was this person more or less correct?

The answer is - it depends. 

Was this a talk about Design Patterns or Silverlight Concepts?  What are the chances that an argument over Model-View-Presenter vs. Model-View-ViewModel would erupt?  I'm of the opinion that there are some basic questions that should be asked by an audience member if these things are a concern. 

Q: Excuse me, could you say a few words about what shortcuts you might be taking when demonstrating this concept? 

That's not hard, and assuming the presenter is knowledgeable and experienced they should be able to quickly describe how the quick sample app they are showing you differs from the real-world applications they have probably written before giving a talk in front of an audience.  If a quick description isn't enough to satisfy an audience member, you can put it on the back burner for after the talk.  If my talk is on the ins and outs of Silverlight Data Binding I might rather not spend time explaining how my data access layer, my presenters, my Commands, and my View Models work.  I have to make an assumption here.  If I'm going to use good patterns in my demo code, I'm going to have to assume that most or all of the audience members have at least passing familiarity with said patterns.  If I'm wrong, I'm going to have to set aside part of my presentation to explain the patterns.  This might be very enriching indeed, but myself and my audience may not be as satisfied as if we'd more thoroughly covered the intended topic.  If I'm right and the audience does have a certain level of pattern knowledge, they'll be thinking themselves about what the appropriate abstractions might be.

There are definitely cases though, beyond just knowing your audience, where it is absolutely important to utilize some patterns and practice separation of concerns within your demo code. 

  1. If the nature of the design affects your overall message
  2. If demonstration of a proper design would help neophytes fall into the Pit of Success easier and not detract from time spent on the Core Concepts of your talk
  3. If the quick-and-dirty demonstration method will not work for common situations

The last one probably needs some explanation, and I'm going to pick on Entity Framework here.  I generally like the Entity Framework, but every single early example I saw was creating an easy to follow breadcrumb trail to the Pit of Failure.  Consider a fairly common ASP.Net web forms scenario:

  1. Get some data objects on page load
  2. Bind objects to web controls
  3. Objects are likely to be updated, throw them in the session
  4. On some event, take data out of the web form controls, merge with object data in session, push back down to the data access layer

There were tons of quick and dirty LINQ to Entities examples with the LINQ query against an EntityContext in some Page_Load event, code behind, or other inappropriate place.  These set you up for disappointment.  If you try to push these objects back down to the database (after a couple of postbacks) using the Entity Framework you're going to get an exception saying that these objects are already a tied to some other EntityContext which is now lost.  If you destroy the EntityContext to get around this, you're going to find that you lost change tracking for your entities and wonder why your updates are updating Zero objects every time.  If you Detach() your objects from the EntityContext, thinking you'll re-attach later, you may find that your Entity relationships have disappeared.  You probably don't want to keep an EntityContext open for the lifetime of a Use Case for all sorts of reasons that should be obvious.

As it turns out, hiding the Entity Framework behind a traditional Data Access Layer and using typical DAO semantics requires some clever Extension methods, a few extra lines of code on your part, resigning yourself to updating more fields than actually changed, and some consideration of how this might cause the whole Entity Framework abstraction to leak out into other parts of your application.  It's still worth it, but I wish I'd seen some more real Entity Framework demonstrations while the excitement was building.

It's my opinion that the level of Architecture you need in demo applications is determined by knowing your audience and knowing how naturally the quick and dirty vanilla demo code can be translated into the design of a production ready application.  Those who attend and present at User Group talks should be ready to ask and answer these questions.



Tuesday, October 21, 2008 11:59:37 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, October 19, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Moving the Selection with the mouse

Now that select and multi-select are working the next logical step is to allow the user to move things around on the design surface, and I have an idea of what I’d like to support. 

·         A single selected component is straightforward: drag and move.

·         If there are multiple components selected, clicking on any one of them should move the entire selection without changing relative space.

The first item is probably best accomplished by handling mouse events and mouse capture on the invisible “Glass” component of the DesignSite.

Refactor: Some of the mouse event handlers in DesignSite were still named Visual_MouseXXX and should be called Glass_MouseXXX now.

Refactor: Right about this time, Silverlight Release To Web came out.  So far, I’ve not had to change anything from my RC0 code.

We need to decide where to wire up the mouse events associated with moving – in the DesignSurface or in the DesignSite.   Since we are already using the ISelectionService within DesignSite, I’ll try there first.  Remember that the “Glass” control in the DesignSite is the 99% transparent overlay on top of the hosted content.  We need to capture the mouse from the Glass component:

        void Glass_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            _selSvc.Select(new List<IDesignableControl> { this });

            _isMoving = true;

            _localMovePoint = e.GetPosition(Glass);

            _surfaceMousePoint = e.GetPosition(DesignParent);

            e.Handled = true;

            Glass.CaptureMouse();

        }

First I test to make sure I can move a single selected component around:

        private void Glass_MouseMove(object sender, MouseEventArgs e)

        {

            if (_isMoving)

            {

                Point surfacePoint = e.GetPosition(DesignParent);

                //Since we can't grab from outside ourself:

                double left = surfacePoint.X - _localMovePoint.X;

                double top = surfacePoint.Y - _localMovePoint.Y;

               

                SetValue(Canvas.LeftProperty, left);

                SetValue(Canvas.TopProperty, top);

            }

        }

This works exactly as I’d expect it to.  In order to move multiple selected components at once, I’m expecting that I’ll have to calculate a relative change from the previous mouse location and iterate across all IDCs in the selection, updating their positions.

My selection-code-under-Glass was clearing the multi-selection and replacing it with a single selection, so when I update the Glass_MouseLeftButtonDown method, everything works.

        void Glass_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            //if this is already selected, we might want to move.

            if ( (_selSvc.SelectionCount > 0 && _selSvc.GetSelection().Contains(this)))

            {

                StartMove(e);

            }

            else if (!_selSvc.GetSelection().Contains(this))

            {

                _selSvc.Select(new List<IDesignableControl> { this });

                StartMove(e);

            }

            e.Handled = true;

        }

 

        private void StartMove(MouseButtonEventArgs e)

        {

            _isMoving = true;

            _localMovePoint = e.GetPosition(Glass);

            _surfaceMousePoint = e.GetPosition(DesignParent);

            Glass.CaptureMouse();

        }

Refactor: I found the app behaved more intuitively when I set it so that clicking on the surface itself would clear the current selection.  This is done by passing null to ISelectionService.Select().

I can now select and move things around on the surface.

In the next article I’m going to finally start working on replacing that section on the right that has said “I am a property grid” for 15 articles so far.  The live demo has been updated, which means you’ll need Silverlight RTW to run it.

Source code: DamonPayne.AGT[14].zip (805.28 KB)



Sunday, October 19, 2008 2:50:48 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, October 14, 2008

Silverlight 2 is a real, shipping product today.

http://www.hanselman.com/blog/Silverlight2IsOut.aspx

Later this week, I'll be converting my development environment and projects (including AGT) over to the Real Deal, and hopefully releasing some stuff at CarSpot too.



Tuesday, October 14, 2008 8:13:23 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 13, 2008

I will not be there due to family being in town, but I encourage you to check out David Palfery's presentation in the Milwaukee area tomorrow night: http://www.wi-ineta.org/.  If you'd like a preview of what he's presenting, check out his blog at http://palfery.spaces.live.com/ .

There's also a Silverlight SIG branch of our User Group now, and I sadly missed the first meeting.  Perhaps in the future Milwaukee Silverlight coders would like to see a presentation on a Silverlight IoC framework and its application to a Visio-type drawing tool?



Monday, October 13, 2008 1:22:26 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

No, I'm not going to the PDC, much to my dismay, so I have to live on the crumbs we'll get from blogs. 

PFX will be a part of the .NET framework 4.0.  This is good news!  I have to wonder, though, if this will make it to Silverlight and the Compact Framework?  I am working on some Silverlight performance benchmark stuff and was contemplating porting some of my own work just to see how much effort it would be.



Monday, October 13, 2008 8:32:04 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, October 09, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Rectangular Lasso

I find it incredibly useful to be able to draw a temporary rectangle on a design surface in order to select multiple Controls at once for moving or property editing.  I’d like to support this feature in AGT as well; I call it the rectangular lasso.  I had a very good notion of how I was going to do this: use a method somewhat similar to how I calculated render size in my resizing code, but for drawing a Rectangle object on my design surface.  I’m going to introduce a new convention for these articles: a quick heading to summarize any time that I find I needed to refactor my design to meet current needs or refine thinking.  Since refactoring is good, these will be green and easy to see.

Refactor: I made a static class called ControlExtensions and included a Generic Method to be more convenient with returning Dependency Property values.  When I tried to use this with the Rectangle code below I realized (duh) that this should not be for Control, but DependencyObject.  A DependencyObjectExtensions class has been introduced.

The stage is set when I click on the design surface Canvas. 

        private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            _isSelecting = true;

            _selectingRect = new Rectangle();

            _selectingRect.StrokeThickness = SELECT_RECT_STROKE_WIDTH;

            _selectingRect.RadiusX = SELECT_RECT_RADIUS_X;

            _selectingRect.RadiusY = SELECT_REDT_RADIUS_Y;

            _selectingRect.Stroke = new SolidColorBrush(Colors.Red);

            _selectingRect.Fill = new SolidColorBrush(Colors.Magenta);

            Point clickLoc = e.GetPosition(LayoutRoot);

            _selectingRect.Opacity = .65;

            _selectingRect.SetValue(Canvas.ZIndexProperty, 100);

            _selectingRect.SetValue(Canvas.LeftProperty, clickLoc.X);

            _selectingRect.SetValue(Canvas.TopProperty, clickLoc.Y);

            _selectAnchor = clickLoc;

            LayoutRoot.Children.Add(_selectingRect);

            LayoutRoot.CaptureMouse();

        }

This sets up the Rectangle for resizing.  It will be on top of all other controls and transparent so we can see the controls beneath it.

Note: since some Silverlight components cannot be extended, one is likely to be working with a lot of UserControls.   I like the convention of keeping the top level content of each UserControl named LayoutRoot regardless of its type, it’s a good name.

We next need to handle the mouse move event as long as the left button is pressed.  I have noticed that various programs with a design surface seem to allow resizing only to the east and south, but selecting in either direction.  Since this seems to be a convention, I’ll follow it. 

        private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)

        {

            _localMousePos = e.GetPosition(this);

            if (_isSelecting)//southeast drag

            {

                double rectLeft = _selectingRect.GetValue<double>(Canvas.LeftProperty);

                double rectTop = _selectingRect.GetValue<double>(Canvas.TopProperty);

                if (rectLeft < _localMousePos.X)

                {

                    double width = _localMousePos.X - rectLeft;

                    double height = _localMousePos.Y - rectTop;

                    _selectingRect.Width = width;

                    _selectingRect.Height = height;

                }

                else // northwest drag

                {

                    double width = _selectAnchor.X - _localMousePos.X;

                    double height = _selectAnchor.Y - _localMousePos.Y;

                    if (width > 0 && height > 0)//need this safety here in case a resize rectangle "crosses" itself.

                    {

                        _selectingRect.Width = width;

                        _selectingRect.Height = height;

                        _selectingRect.SetValue(Canvas.LeftProperty, _localMousePos.X);

                        _selectingRect.SetValue(Canvas.TopProperty, _localMousePos.Y);

                    }

                }

            }

        }

Refactor: When testing the drawing of the selection Rectangle, I found that when resizing controls on the surface I would also have a tag-along selection rectangle.  The DesignSite resizing Border needed to mark the mouse click event has Handled=true in order to prevent this.

Now when the user releases the left mouse button, we destroy the selection Rectangle:

        private void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            _isSelecting = false;

            LayoutRoot.ReleaseMouseCapture();

            LayoutRoot.Children.Remove(_selectingRect);

            _selectingRect = null;

        }

This now allows me to lasso in several controls at once like so:

The last aspect of this feature is to hook into the ISelectionService to select any components that are within the Rectangle bounds as I resize the Rectangle.  We need to create a SelectLassoComponents method and call it from within the MouseMove event.  As soon as this is implemented, I find some new strange behavior.  FindElementsInHostCoordinates does not work like I’d hoped.  It seems to need a much bigger Rectangle than it appears to visually to call a “hit” for a control:

       

So, I add logging to see the size of the rectangle I’m drawing in my message window.  I see nothing but extremely odd behavior.  The code for selecting the lassoed controls uses the VisaulTreeHelper class as follows:

        protected virtual void SelectLassoComponents(Rectangle lasso)

        {           

            double left = lasso.GetValue<double>(Canvas.LeftProperty);

            double top = lasso.GetValue<double>(Canvas.TopProperty);

            double width = lasso.Width;

            double height = lasso.Height;

            Rect r = new Rect(left,top,width,height);           

            IEnumerable<UIElement> hits =

                VisualTreeHelper.FindElementsInHostCoordinates(r, LayoutRoot);

VisualTreeHelper is not yet documented on MSDN, but my logging tells me that the Rect is being drawn with the correct bounds.  I had to write my own simple hit test function which will register a hit if any of the four corners of a control falls within the lasso.  This required a FrameworkElementExtensions class to contain a corner method:

        public static Point[] GetCanvasCorners(this FrameworkElement u)

        {

            if (!(u.Parent is Canvas))

            {

                throw new ArgumentException("This only works if FrameworkElement is on a Canas!");

            }

 

            Point[] corners = new Point[4];

 

            double left = u.GetValue<double>(Canvas.LeftProperty);

            double top = u.GetValue<double>(Canvas.TopProperty);

            double width = u.Width;

            double height = u.Height;

            if (double.IsNaN(width) || double.IsNaN(height))

            {

                width = u.RenderSize.Width;

                height = u.RenderSize.Height;

            }

 

            corners[0] = new Point(left, top);

            corners[1] = new Point(left + width, top);

            corners[2] = new Point(left, top + height);

            corners[3] = new Point(left + width, top + height);

 

            return corners;

        }

Following this, we can use a more basic hit testing algorithm like what is shown here, within the SelectLassoComponents implementation.

        protected virtual void SelectLassoComponents(Rectangle lasso)//TODO: make hit test strategy pluggable

        {           

            double left = lasso.GetValue<double>(Canvas.LeftProperty);

            double top = lasso.GetValue<double>(Canvas.TopProperty);

            double width = lasso.Width;

            double height = lasso.Height;

            Rect r = new Rect(left,top,width,height);           

            List<IDesignableControl> selection = new List<IDesignableControl>();

 

            foreach (var u in LayoutRoot.Children)

            {

                if (u is IDesignableControl)

                {

                    IDesignableControl test = (IDesignableControl)u;

                    Point[] corners = test.Visual.GetCanvasCorners();

                    for (int i = 0; i < corners.Length; ++i)

                    {

                        if (r.Contains(corners[i]))

                        {

                            selection.Add(test);

                            break;

                        }

                        else

                        {

                            Log.Log(new DamonPayne.AG.IoC.Types.LogMessage

                            {

                                Level = DamonPayne.AG.IoC.Types.LogLevels.Debug,

                                Message = r.ToString() + " does not contain " + corners[i]

                            });

                        }

                    }

                }

            }

 

            SelectionSvc.Select(selection);

        }

This feels dirty, like I’m still thinking like a Winforms developer, but I’m testing so far with controls that are not Transformed or anything hokey, so I’m disappointed that the VisualTreeHelper method misbehaved on even the simplest case.  This code works exactly as I’d hope it to.  I’m ready to set the lasso aside and move on.

The live demo has been updated!

Source code: DamonPayne.AGT[13].zip (1.47 MB)



Thursday, October 09, 2008 7:49:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, October 08, 2008

I have had a couple of requests to post the entire source code for my Silverlight 2 Image carousel.  I plan on updating the code for RC0, cleaning it up, and making it not specific to Images, and posting the code here.  Stay tuned.



Wednesday, October 08, 2008 10:09:50 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, October 07, 2008

This is a roundup for the AGT project: what have we done so far?

If you’re just joining me, I always put the following text at the beginning of each article in the series I’m currently working on:

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.

What I'm working on here is a framwork I can use to build something that looks and behaves like a Visual Studio Shell or a Visio, but runs inside the browser using Silverlight.  I of course won’t claim to have duplicated the functionality in those tools, which is massive.  Rather, I’m going for the “80/20” rule; I’m hoping that I can achieve huge amounts of functionality for very little work with an implementation that is understandable yet flexible.  I plan on putting this on Codeplex once I get to a decent v1 milestone. 

Summary of the ground covered so far:

·         AGT[0] – Vision statement

·         AGT[1] – Initial thoughts on Service/plug-in/add-in/module strategy and Composite UI management

·         AGT[2] – Dependency injection, Presenters, Event Aggregation

·         AGT[3] – Creating the initial designer metaphors

·         AGT[4] – Toolbox service, ViewModel, Data binding with INotifyCollectionChanged

·         AGT[5] – Generating dynamic proxies for Service providers using Reflection Emit

·         AGT[6] – Creating a design for drag/drop interactions in Silverlight.

·         AGT[7] – Implementing drag ‘n drop from the Toolbox to the Design surface

·         AGT[8] – Code refactoring and introduction of Unit Tests for Silverlight

·         AGT[9] – Visual refactoring, new Toolbox items

·         AGT[10] – Creating a Selection service, publish live demo

·         AGT[11] – Updating the codebase for Silverlight 2 RC0

·         AGT[12] – Resizing items on the designer surface

This is Reality Blogging, I really am writing the code as I go.  Some of the embarrassing refactoring should serve as proof of this.  Still, it’s completely fair to think about a roadmap and potential problems.  I do have an idea of where all this is going and what might constitute a reasonable v1 release.  Here are some additional things I'd like to support.

1.       Multi-select items by drawing a rectangle “lasso” on the surface

2.       Moving  the selected stuff around on the surface with the mouse and keyboard

3.       Property Editing contract: When an IDesignableControl is selected, how will I determine what properties show up in my “property grid” and how they look?

4.       Property editing grid: with the above decided, a PropertyGrid will have to be built from scratch!

5.       Supporting Silverlight 2’s Full Screen mode

6.       Support zoom in/zoom out at the document level

7.       Change the look of the designer using some kind of Settings service.

8.       Design Surface Behavior concepts:  I have this idea that I might provide flexibility as to how things look and behave on the Designer Surface using a “behavior chain”, which I envision will function as a set of mini-Services hosted by the Design Surface itself. I thought of some things I might do to prove the design works:

a.       Alignment snap-lines ala Visual Studio?

b.      Rotate “adorner” to allow things to be rotated?

c.       Measure adorner to selected items show a “size”?

d.      Refactor multi-select to be a behavior of this type?

9.       Serialization/IDesignableControl<T>: In order to be useful, my “drawings” will need to be saved and re-loaded into the designer!  I need to serialize the scene graph into some kind of "document".

10.   Hierarchy of service containers via some notion of Context.  Stay tuned for explanation on this one…

11.   “Stencil” sets: how to provide drop-in flexibility for “what kind of document is this?”

12.   Dedicated refactoring articles as I go.

If I am correct and these things can mostly be done in one article each, I might be up to something like AGT[30] before I’m ready to put this on Codeplex as an v1 release. I'm excited about what's to come, but I only have so much time for research so I will take each step as I can.



Tuesday, October 07, 2008 12:33:30 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 06, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Resizing

As I look at the project so far, it seems somehow more natural to want to move things before selecting or resizing, but the notion of Selection had to come first, which has a dependency on my Site metaphor.  Since the selection border is already in place, why not move on to resizing next?

While contemplating resizing, rotation (which I plan on adding eventually), and selection I had a dilemma.  I felt there were two main paths:

1.       Draw adorners.  This means the IDesignableControl lives on the surface mostly as itself, and when an interesting event happens (like selection) we have the surface draw a border with the familiar “grab knobs” at the corners. 

2.       Container/Site: I first thought of creating a Grid to hold the IDesignableControl within it, since this would provide the table structure needed to draw “knobs” as well as the familiar selection border.

I wrote the code for the Grid first while working in my third office (http://www.ale-house.com/alehouse/index.php?option=com_content&task=view&id=23&Itemid=57 ) without the source for the project, which lives on the workstation in my second office (http://www.flickr.com/photos/damonrpayne/528817886/ ) and ultimately didn’t’ like it, but I did learn enough to see that a Silverlight Border would make resizing incredibly easy.  I have a vague notion of an IDesignSurfaceBehavior I can use for true Adorner flexibility later, but for selection and resizing using a UserControl with a Border was just so simple I had to start by going down this path.

DesignSite

The UserControl serving as border container is the DesignSite.  It has a Width and Height of Auto and the Border has a Width and Height of Auto as well, to make resizing a piece of cake.  The XAML couldn’t be easier.

        <Border x:Name="SiteBorder" BorderThickness="0" BorderBrush="{StaticResource SelectionBorderBrush}" CornerRadius="7" Cursor="Hand" MouseLeftButtonDown="SiteBorder_MouseLeftButtonDown" MouseLeftButtonUp="SiteBorder_MouseLeftButtonUp" MouseMove="SiteBorder_MouseMove">

            <Border.Child>

                <TextBlock>Default Content</TextBlock>

            </Border.Child>

        </Border>

The code is fairly straightforward too.  For most things we are using a pattern of delegation to the contained instance to make future designer interactions easier.  In order to properly calculate resizing, I needed to be able to get at the actual design surface itself, so I created an IDesigner interface which is implemented by DesignSurface.

    public interface IDesigner : IService

    {

  UserControl VisualRoot { get; }

  Canvas Surface { get; }

    }

I have a feeling I’ll be adding to that later.  Here is the mouse code in DesignSite:

        private void SiteBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {           

            _resizing = true;

            SiteBorder.CaptureMouse();

        }

 

        private void SiteBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            _resizing = false;

            SiteBorder.ReleaseMouseCapture();

        }

 

        private void SiteBorder_MouseMove(object sender, MouseEventArgs e)

        {

            if (_resizing)

            {

                Point resizePoint = e.GetPosition(_designer.VisualRoot);

                double left = SiteBorder.GetValue<double>(Canvas.LeftProperty);

                double top = SiteBorder.GetValue<double>(Canvas.TopProperty);

                double newWidth = left + resizePoint.X;

                double newHeight = top + resizePoint.Y;

                Control c = (Control)SiteBorder.Child;

                if (newWidth > 5 && newHeight > 5)

                {

                    c.Width = newWidth;

                    c.Height = newHeight;

                }               

            }

        }

And now, when I run it, everything goes to hell.  Handling resizing seems to have become my first serious problem.  In order to study the issue, I created a DummyButton IDesignableControl, which exposes even more problems. 

A Silverlight control with size set to Auto (take up its whole container) returns NaN for Width and Height,  {0,0} for RenderSize, 0.0 for ActualWidth and ActualHeight, {0,0} for DesiredSize, 0.0 for MinWidth and MinHeight.  This makes it hard to measure or do any calculations on until it is actually placed in a container.  Calling Control.Measure does not seem to fix the issue.  I was unable to create my Drag representation of the DummyButton until I set its containing UserControl to have an actual size.  Attempting to select the button on the surface reveals another issue: the button is swallowing the click event before my code can react to it.  I’d like to handle this in a generic fashion.

I set about making a “glass” idea: placing an almost entirely transparent control in front of the real content in the Z order.  Getting this to cover the entirety of the real content led me back to the same lack of ActualWidth and friends that started this mess. 

Reality Blogging, cue RC0

OK, everything above this heading was written pre-RC0 and I was clearly floundering, I call time out.  I need to restate and reform my goals:

·         My DummyButton test shows that I need to refine IDesignableControl and how things ought to resize on the DesignSurface.  I am so far setting width/height of the IDesignableControl.Visual when dragging the Border to resize.  This is only appropriate in some cases. For a Button, sure, I’d want to set its bounds independent of its FontSize or other properties.  For the furniture and speakers, I’d actually want to apply a Transform since a huge red square with a chair in the corner or a small red square showing part of a chair is obviously not my intent.

·         Following from the above, IDesignableControl.Scalable and IDesignableControl.Transformable need to be re-thought.  I need a property stating if the IDC{IDesignableControl} is to be resized by changing Width & Height, if not, Transformable should be checked.  Both these properties being false means we should not resize the IDC at all.

·         There’s too much code in DesignSite.  Event wire up related to sizing is possibly fine, but we should keep things in whatever IDesignTypeCreator implementation wherever possible.

Now I feel like I’ve got a better plan, even if the Measuring issue is still waiting.  First I refactor IDC.Scalable and include an appropriate comment.

        /// <summary>

        /// Return true if this IDesignableControl should be resized by changing Width & Height

        /// </summary>

        bool IsBoundsResizable { get; }

Next, IDC.Transformable:

        /// <summary>

        /// Can a ScaleTransform etc. be used to resize this control?

        /// </summary>

        bool IsTransformable { get; }

Next I setup a test. The DummyButton will be IsBoundsResizable=true, and the Red Chair will be IsBoundsResizable=fasle/IsTransformable=true.

Debugging Events

The next step I take is to set up some code to debug the various mouse position, sizing, and layout events for the Border in DesignSite.  I tend to do this by instrumenting the code rather than using the debugger.  What good is a MouseLeftButtonDown event on a visual control when the debugger will receive the MouseLeftButtonUp event?  I have to use the ILogService and my message window to see when/how some things are happening.

Layout Cycle Detected

If you subscribe to a LayoutUpdated event, it’s best not to touch the GUI in any way from within this event handler.  During my testing, I would use the ILogService to send a message stating that my DesignSite had its layout updated.  This, in turn, fires the LayoutUpdated event which is counterintuitive.  One might think that LayoutUpdated means “Layout of the current control” but in fact means a layout or property change of any item in the visual tree of the Silverlight plug-in.  Obviously touching the visual tree from here will melt circuits.

Resizing

With a more clear idea of precisely what I was trying to do, I went back to working on my resizing code. When my Border has mouse capture, I can choose how to resize its content:

        private void SiteBorder_MouseMove(object sender, MouseEventArgs e)

        {

            if (_resizing)

            {

                if (HostedContent.IsBoundsResizable)

                {

                    ResizeContent(e);

                }

                else

                {

                    TransformContent(e);

                }               

            }

        }

I have to admit it took quite a while to get the ResizeContent method right.  At the end of the day, this was just facing reality and doing what worked rather than refusing to accept how”Auto”, “Stretch”, and “Fill” did not live up to expectations.  I have to set five different Controls’ sizes manually to make my bounds resizing work:

        private void ResizeContent(MouseEventArgs e)

        {

            Point resizePoint = e.GetPosition(DesignParent);

            //Determine where the DesignSite is on parent

            double left = this.GetValue<double>(Canvas.LeftProperty);

            double top = this.GetValue<double>(Canvas.TopProperty);

            double newWidth = resizePoint.X - left;

            double newHeight = resizePoint.Y - top;

 

            //Take border into account

            double innerWidth = newWidth - (2 * UNIFORM_BORDER_THICKNESS);

            double innerHeight = newHeight - (2 * UNIFORM_BORDER_THICKNESS);

 

            if (newWidth > 5 && newHeight > 5)

            {

                _content.Visual.Width = innerWidth;

                _content.Visual.Height = innerHeight;

                Glass.Width = innerWidth;

                Glass.Height = innerHeight;

                LayoutRoot.Width = newWidth;

                LayoutRoot.Height = newHeight;

               

                ContentCanvas.Width = innerWidth;

                ContentCanvas.Height = innerHeight;

 

                SiteBorder.Width = newWidth;

                SiteBorder.Height = newHeight;

 

            }

        }

Having accepted this reality, my “transform” resizing worked the first time:

        private void TransformContent(MouseEventArgs e)

        {

            Point resizePoint = e.GetPosition(DesignParent);

            //Determine where the DesignSite is on parent

            double left = this.GetValue<double>(Canvas.LeftProperty);

            double top = this.GetValue<double>(Canvas.TopProperty);

            double newWidth = resizePoint.X - left;

            double newHeight = resizePoint.Y - top;

            //We need to attain a render size equal to our new border inner bounds,

            //so we'll calculate what scale transform would get us there

            double innerWidth = newWidth - (2 * UNIFORM_BORDER_THICKNESS);

            double innerHeight = newHeight - (2 * UNIFORM_BORDER_THICKNESS);

 

            SiteBorder.Width = newWidth;

            SiteBorder.Height = newHeight;

            //

            Glass.Width = innerWidth;

            Glass.Height = innerHeight;

            //

            ContentCanvas.Width = innerWidth;

            ContentCanvas.Height = innerHeight;

            //

            ScaleTransform st = new ScaleTransform();

            st.ScaleX = innerWidth / HostedContent.Visual.ActualWidth;

            st.ScaleY = innerHeight / HostedContent.Visual.ActualHeight;

            HostedContent.Visual.RenderTransform = st;

        }

Now, I can finally have large buttons, small couches, and huge speakers on my design surface:

… All perfectly scaled according to their needs by naturally grabbing and dragging the border.  Hooray for vector graphics.  Note to self: every single flaw in artwork is readily apparent when scaled far larger than I drew it.

Conclusion

This article was a bit of a mess since Silverlight 2 RC0 happened right in the middle of it and my vision was not re-adjusted early enough when I started realizing there were issues.  There are also still cases where I am obviously thinking like a WinForms developer.  I kept thinking to myself how easy this would be if I could do work by overriding an OnPaint virtual method.  Still, I finally got where I wanted to be and learned a few more things about Silverlight in the process.  Since I’ve already given thought to one more bit of sauce before I write code to move things around on the surface I will visit the “rectangular lasso” next.

Source code: DamonPayne.AGT[12].zip (1.3 MB)



Monday, October 06, 2008 10:32:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, October 01, 2008

I don’t have any ideas yet, but Netflix is one of my favorite services.   This is completely awesome.  I hope they have the APIs enabled for cross-domain stuff so I could perhaps do some Silverlight mojo without having to Proxy the calls.

http://developer.netflix.com/page

Actually, in the process of writing this email, I did get some ideas for uses of the Netflix API.  I'm not sharing yet!



Wednesday, October 01, 2008 1:52:56 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, September 27, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

RC0

As promised, my next task was to make any changes needed to prepare the app so far for working with the RC0 Silverlight release.

Object Tag

The first thing I noticed is that when I tried to run the application I was presented with “Get Silverlight”.  I figured the version # had changed, but it was actually the type attribute of the object tag:

    <object data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%">

          <param name="source" value="ClientBin/DamonPayne.HTLayout.xap"/>

          <param name="onerror" value="onSilverlightError" />

          <param name="background" value="white" />

          <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">

            <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>

          </a>

      </object>   

Note the type is now “application/x-silverlight-2”.

XAML weirdness

The next error I noticed was a seemingly uncatchable error that percolated all the way up to the onSilverlightError JavaScript function.

“Can not set ItemTemplate and DisplayMemberPath simultaneously.”

Looking at the XAML, this makes sense.

        <ListBox x:Name="_itemLst" Grid.Row="1" DisplayMemberPath="Name"  ItemsSource="{Binding ToolboxItems}" SelectedItem="{Binding Path=SelectedToolboxItem, Mode=TwoWay}">

            <ListBox.ItemTemplate>

                <DataTemplate>

                    <StackPanel Orientation="Horizontal" >

                        <TextBlock Text="{Binding Name}"

This makes sense, it just didn’t cause an error before.  I’m setting DisplayMemberPath in XAML, which is then not used since I’ve provided the entire ItemTemplate.  It would be useful if the error told me which XAML file the error is in, but this is a small project so far and future Silverlight developers will be starting out with Silverlight 2 Release.

HitTest missed

At this point I thought I’d better do a Clean Solution just to be safe, and sure enough this turned up another issue.  At some point, my DesignSurface.HitTest method (required by IDropTarget) disappeared.  The Clean Solution found this out for me.  Looking back through my code snapshots taken at the end of each article, it’s been gone for quite some time.  This behavior from VS2008/Silverlight Tools is just not ok.  This was my last breaking change though.  UIElement.HitTest is gone, replaced with a method in VisualTreeHelper:

        public IEnumerable<UIElement> HitTest(Point p)

        {

            return VisualTreeHelper.FindElementsInHostCoordinates(p, LayoutRoot);

   }

Moving On

I find now that my Selection code is absolutely broken, but that was under repair anyway.

Source code: Because the code was in a state of flux pending the selection/sizing updates, the next source code will be at the end of AGT[12].



Saturday, September 27, 2008 12:31:33 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, September 26, 2008

You have probably seen that Silverlight RC 0 is now available: http://weblogs.asp.net/scottgu/archive/2008/09/25/silverlight-2-release-candidate-now-available.aspx

I was in the middle of writing AGT[11] and got sick, requiring a 16 hour sleeping spree, and I'm still not over it. AGT[11] also represented some frustrating material, so it was going slow.  Figuring out the Silverlight Layout-->Measure-->Clip-->Render process well enough to acheive my next goal is turning out to be challenging.  I'll preface it with some recommended reading.  At any rate, the material for AGT[11] will now become AGT[12].  The articles and the live demo are immediately switching over to use Silverlight RC0 before I accumulate any more breaking changes or write code to Measure behavior that changes.  Some of the solutions I was pursuing just became private/internal/sealed as of yesterday.

Recommended reading:

http://msdn.microsoft.com/en-us/library/cc645025(VS.95).aspx

http://msdn.microsoft.com/en-us/library/cc189087(VS.95).aspx

http://blogs.msdn.com/silverlight_sdk/archive/2008/05/06/more-on-layout-and-the-layoutinformation-apis.aspx

http://silverlight.net/forums/t/20520.aspx

http://nerddawg.blogspot.com/2008/04/silverlight-2-layout-and-rendering.html

http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.layoutinformation_members(VS.95).aspx

 



Friday, September 26, 2008 3:56:32 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, September 22, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008.   This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Selection

Now that we’ve got things on the surface, we need to think about selecting, moving, editing, and resizing them.  It makes sense for Selection to come first.

Selection is slightly more complicated than it sounds.  In a tool like VS2008 or Visio things could be added or removed from the selection in several ways:

·         Clicking on a component

·         Control+Click on multiple components to select and deselect

·         Shift+Click to add contiguous components to the selection

·         Click and draw a rectangle, selecting components within the bounds of said rectangle.

Since I’m extending the olive branch to the dozens and dozens of unfortunate Mac users in the world, I’ll have to make any gesture code I write smart enough to not use any normal keys that are missing from the Mac, such as: Control, Window Key, Right-click Key, Pause/Break, up arrow, and the letter Q.

Back in the Dark Ages when I was writing code to host the WinForms 2 design surface, I think my selection service implementation was quite a few lines of code.  While I still like the idea of a selection service, I’m not going to go look at the old code and corrupt my pure thoughts.  First, let’s create a cross platform Keyboard service:

    public class CrossPlatformKeyboardService : IKeyboardService

    {

        /// <summary>

        /// Control key, or open-apple on the Mac "platform"

        /// </summary>

        public bool ControlKeyDown

        {

            get

            {

                return ( Test(ModifierKeys.Control) || Test(ModifierKeys.Apple));

            }

        }

 

        public bool AltKeyDown

        {

            get { return Test(ModifierKeys.Alt); }

        }

 

        public bool ShiftDown

        {

            get { return Test(ModifierKeys.Shift); }

        }

 

        protected bool Test(ModifierKeys target)

        {

            return target == (target & Keyboard.Modifiers);

        }

Next I’ll define what I expect the interface for a selection service to be.

    public interface ISelectionService : IService

    {

        void SetSelectedControls(IList<IDesignableControl> selection);

        IList<IDesignableControl> GetSelection();

        int SelectionCount { get; }

        IDesignableControl PrimarySelection { get; }

        event EventHandler SelectionChanged;

    }

In WinForms, adding to the ISelectionService can optionally come with a parameter of type “SelectionType”, which is a discriminator for things like adding to a selection vs. starting a new selection.  I’d rather leave those details behind the ISelectionService wherever possible.  You will also note that I am using a plain old .Net event here and not something from EventAggregator.  I feel this is highly appropriate in this case.  The EventAggregator exists so that components can respond to interesting events without referencing each other, but selection events are specific to this Service, and components that need ISelectionService will magically receive it from the container.   Now I can start working on a default ISelectionService implementation, with a dependency on IKeyboardService.

Siteing, not Sighting

We need to take another step before Selection can make sense.  The WinForms designer has the notion of an ISite, where an ISite is an adapter between a designed component and its designer.  Once sited, the component can request various things of its container.  While not quite what I’m about to do, it’s a point for interested users to research.   I will explain this concept further in the next article.  I have created a UserControl called DesignSite.  DesignSite contains a border whose thickness is set to zero by default.  Inside DefaultDesignTypeCreator I shove the real IDesignableControl inside my DesignSite and let DesignSite handle the selection code when the real IDesignableControl is clicked on.

Back to Selection

The Site mentioned above wires up selection by resolving the ISelectionService.  Here, then, is the selection service implementation.

    public class DefaultSelectionService : ISelectionService

    {

        public DefaultSelectionService()

        {

            _selection = new List<IDesignableControl>();

        }

 

        public IKeyboardService KBService { get; set; }

 

        private List<IDesignableControl> _selection;

 

        public void Select(System.Collections.Generic.IList<IDesignableControl> incoming)

        {

            if (!KBService.ControlKeyDown)

            {

                _selection.Clear();

                _selection.AddRange(incoming);

                OnSelectionChanged();           

            }

            else

            {

                foreach (IDesignableControl idc in incoming)

                {

                    if (!_selection.Contains(idc))

                    {

                        _selection.Add(idc);

                    }

                    OnSelectionChanged();           

                }

            }           

        }

 

        public System.Collections.Generic.IList<IDesignableControl> GetSelection()

        {

            return _selection;

        }

 

        public int SelectionCount

        {

            get { return _selection.Count; }

        }

 

        public IDesignableControl PrimarySelection

        {

            get

            {

                return _selection[0];

            }

        }

 

        public event EventHandler SelectionChanged;

 

        protected void OnSelectionChanged()

        {

            if (null != SelectionChanged)

            {

                SelectionChanged(this, EventArgs.Empty);

            }

        }

Much simpler and shorter than I remember the WinForms implementation I remember.  We’ll see if I eat crow for saying so later.  Here is my site-style selection with a single component selected.

Shown here with multiple components selected by holding in Control or Open Apple:

You will note I don’t have any little “knobs” on the corners or anything.  I like how this looks better with a solid border and a gradient brush.  As we saw with Couch v1, perhaps my taste in visual appeal should not be trusted.  Speaking of couches, I have a chair now too.  You can take a look at my freshly painted Red Chair in the live demo.  Live demo….?

More ControlExtensions

Ever since being enlightened by Generics (the answer to everything) using the (cast) bothers me.  Casting using “as” bothers me more.  For this reason, I don’t know why the whole DependencyProperty framework deals with getting and setting of values as Object.  When I ported some code from Silverlight 2 beta 1 to beta 2, some of it was broken because I was using SetValue(Canvas.Left, 3) when in fact Canvas.Left wanted to be of type double and some auto-conversion was lost in the move to beta 2.  This error only pops up at runtime since SetValue takes type Object.  At least I can save myself some casting here and there by adding another extension method:

        public static T GetValue<T>(this DependencyObject d, DependencyProperty p)

        {

            return (T)d.GetValue(p);

        }

Which allows glorious code like:

double left = SiteBorder.GetValue<double>(Canvas.LeftProperty);

It isn’t much but I’ll take it.

Conclusion & Next Steps

I have created a live demo at http://www.damonpayne.com/agt ; obviously this is a work in progress but feedback is welcome. 

I have a pretty good idea how I’m going to do resizing, that will come next.  After that I will do multi-select by drawing a rectangle and then Moving.  After moving works I will have to think of how I want object editing to work, some kind of Property Grid I’m sure.  From there, I’ll have to take stock of where I’m at, review my goals, and decide what to do next.

Source code:DamonPayne.AGT[10].zip (1.28 MB)



Monday, September 22, 2008 9:28:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, September 21, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things. Usually an idea is presented only in its finished form. The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches. The second goal, and the example vehicle for the evolution aspect, is an extensible Design Surface for Silverlight similar to what we have in Visual Studio 2008. This type of application has all sorts of interesting uses. My example is a Home Theater layout tool. Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Visual Refactoring

Since this is a Silverlight application I thought I should spend some time making it look good. I hit my frustration limit in a very short period of time and what you see here is as far as I got. I am guessing Styling is not entirely baked in Silverlight 2 beta 2, or else doing a complete control template is really the way to go.

My first issue was with fonts. I downloaded a copy of the Trajan Regular font. Ever since Klipsch started using Trajan pro in the Palladium branding I’ve been digging the Trajan font family. At any rate, it seems that Silverlight is very picky about using extra fonts, be they set from a style or per control. Worse, it’s very difficult to track down where the issue might be. I have three primary tools available to me for Silverlight debugging: Blend 2.5 June CTP, VS2008 SP1, and running the application for inspection. Debugging is not fun when all three tools show different output, check out the ToolboxView:

clip_image002

Blend shows the correct font and color. VS2008 shows the correct nothing. Runtime shows the correct color but not font. I’ve tried obvious things like double checking relative paths and so forth. At this point I’m admitting defeat and moving on. At least my bad taste and visual look stolen from Klipschcorner’s CSS is better than black and grey. Right? Let’s skip to the punchline, here is what the application looks like now:

clip_image004

Couch++

I tricked a visual designer into making me a better purple couch. This person happens to be an extreme Adobe fanboy, to the degree that they didn’t believe me when I said there were other drawing programs for both vector and raster graphics. The Adobe fans are easily worse than the Mac fans. At any rate, that sure looks like a couch, at least. It’s rather large in relation to the design surface, but we’ll fix that with resizification later.

Speakers

I haven’t really thought of what all I want to include in the example HT Layout program, but I figured some speakers would be nice. I’m getting slightly better at drawing some things in Blend: these speakers look better than my original couch. If you’re not familiar with horn-loaded speakers you’ll have to trust me that the white horn shape is actually a reasonable caricature.

Conclusion

I’ll refactor later as I get to read more about the control templating and style creation. I think the app is starting to look like a real program, and we’re still less than 1000 lines of code. The next articles are not written yet, but the next step is to implement functionality that allows me to move, resize, and otherwise Transform things once they are on the designer surface. As it turns out, this is a very interesting problem for all sorts of reasons. I’m not breaking my Reality Blogging pledge, but remember I’ve done this in WinForms before, and I recall things like “selection” being more complex than it sounds: http://msdn.microsoft.com/en-us/library/system.componentmodel.design.iselectionservice_members.aspx . Once selection is implemented moving and resizing come free in WinForms, and I’ve got to build those from scratch now. I’m sure I’ll be spending some time in traffic this week and I’ll spend many mental cycles thinking about the interactions.

Source Code:DamonPayne.AGT[9].zip (1.26 MB)



Sunday, September 21, 2008 7:25:35 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible design-time environment similar to what we have in Visual Studio 2008.  This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Code Refactoring

I’m eager to get on to some of the cool next steps like the ability to move and resize things on the Design Surface, but my TODOs are starting to pile up.  I’d rather not get too far into this and find that some fundamental thing that was bothering me is now a real issue.  Using the Task List feature in VS2008, I’ve got 20 things I should at least look at.

Namespaces

I’ve been thinking lately about some other Silverlight projects I have on the back burner, and how nice it would be to keep them in mind for the IoC stuff.  Therefore, I should rename DamonPayne.AGT.IoC to just DamonPayne.AG.IoC.  I like the fact that VS2008 makes the default namespace of a project match the project name, but the tooling stops there.  I have to rename the project, edit the default namespace, edit the assembly name, and do a global find/replace on the top level namespace.  Lame.  58 occurances replaced, and the Design and HTLayout projects reflect the new name; it even built the first time.

Events

While sitting in traffic I had the idea to overload += for my AggregateEvent<T> and make it feel more like a built in .NET event type.  As it turns out this won’t work the way I wanted it too so I erased that TODO.  I also got rid of the static “Test” method in EventAggregator.

Reflection

I have several TODOs related to reflection code.  The first one suggests Caching Type and Property information to make reflection go faster.  I’ll leave that alone for now and come back to it.

Tidy up: I found that there is a Type.EmptyTypes static var, similar to EventArgs.Empty.  I found three places where I could substitute Type.EmptyTypes.

I also found that I had some duplicate interface code and I could add some things to my TypeExtensions static class:

       public static bool ImplementsInterface(this Type t, Type intefaceType)

        {

            if (intefaceType.IsInterface)

            {

                Type[] interfaces = t.GetInterfaces();

                if (interfaces.Contains<Type>(intefaceType))

                {

                    return true;

                }

            }

            return false;

        }

 

        public static bool ImplementsInterface(this object o, Type intefaceType)

        {

            return ImplementsInterface(o.GetType(), intefaceType);

        }  

I was able to go through ServiceManager and ComponentBuilder and clean up some code using these Extension methods.

Several calls to invoking a Type’s default constructor can be replaced with Activator.CreateInstance; this was done throughout.  The 1-arg constructor for Presenter types was also replaced with a call to Activator.

Control Extensions

On suspicion that I would need the ability to scale controls without distorting their aspect ratio in the future, I left myself a note to create an extension method to determine an aspect ratio preserving method:

    public static class ControlExtensions

    {

        public static double UniformScaleAmount(this Control c, double maxDimension)

        {

            double originaltWidth = c.Width;

            double originalHeight = c.Height;

            double uniformScaleAmount = Math.Min(maxDimension / originaltWidth, maxDimension/ originalHeight);

            return uniformScaleAmount;

        }

    }

At this point, I am staring sideways with some dread at the remaining TODO items.  The remaining items involve:

1.       Revisit the relationship between ServiceManager and ComponentBuilder to see what, if anything, should be done about the crosstalk.

2.       The ToolboxCategory code doesn’t work how I’d like, and fixing it will involve a lot of digging deeper on the Silverlight control templating framework.

3.       There are several visual notes I’ve made to myself, I will address those in the next article.

4.       Something is amuck with InterfaceMocker, it only works once.

5.       I need to decide how I want configuration to work.

Configuration can have its own article I think, for now I’ll at least look into ServiceManager, ComponentBuilder, and InterfaceMocker.

Reflection Emit Redux

Inside ServiceManager.GenerateProxy, I did not take into account the fact that more than one client may ask for a given interface implementation.  In my startup code, I was able to get “Duplicate Type name in assembly” from time to time.  I just needed to add a check before building the type mock:

private static Dictionary<string, object> _proxies;

            string proxyName = t.Name+"TempProxy";

            if (_proxies.ContainsKey(proxyName))

            {

                return _proxies[proxyName];

            }

 

            object o = null;

            ModuleBuilder module = GetDynamicModuleBuilder();

            //

            TypeBuilder typeBuilder = module.DefineType(proxyName,

                TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.Class,typeof(object) );

            typeBuilder.AddInterfaceImplementation(t);

No more proxy errors.

ServiceManager loves ComponentBuilder

As soon as I introduced ComponentBuilder I should have moved all object creation code to it.  But I didn’t, so now here I am looking at several TODO items.  From ServiceManager.ObtainDefaultInstance:

                o = Activator.CreateInstance(t);

                //TODO: maybe use the ComponentBuilder to create the damn thing in the first place

                ComponentBuilder.ResolveServiceDependencies(o);

                ComponentBuilder.BuildPresenters(o);

ComponentBuilder.Create:

        public static T Create<T>() where T :new ()

        {

            T instance = new T();

 

            ResolveServiceDependencies(instance);

            BuildPresenters(instance);

            ServiceManager.ManageInstance(instance);//TODO: verify this was the right design choice later

 

            return instance;

        }

Furthur, ServiceManager.ManageInstance (which might have been a hairy issue otherwise) is used from only a single place, ComponentBuilder.Create.  Creating a non-generic override of Create is step 1:

        public static T Create<T>() where T :new ()

        {

            T instance = default(T);

            instance = (T)Create(typeof(T));          

            return instance;

        }

 

        public static object Create(Type t)

        {

            object instance = Activator.CreateInstance(t);

            ResolveServiceDependencies(instance);

            BuildPresenters(instance);

            return instance;

        }

I hate having to go back and write code that involves casting and Type, when generics are so much cleaner, but such is life.  While chasing down the resulting bugs, I realized Manage(List<Type> types) and ManageInstance(object provider) were almost the same method.  The Manage method is refactored to call ManageInstance:

        public static void Manage(List<Type> types)

        {

            Type baseServiceType = typeof(IService);

 

            foreach (Type t in types)

            {

                object instance = ObtainDefaultInstance(t);

                ManageInstance(instance);

            }

        }

Lovely, more TODOs off my list and some unintended good side effects as well.

Unit Testing

Unit Tests allow us to refactor with impunity.  The fact that this project was ~500 loc doesn’t hurt either.

I Google “Silverlight 2 beta 2 unit test” and look what I find: http://code.msdn.microsoft.com/silverlightut/Release/ProjectReleases.aspx?ReleaseId=1543

I have to admit I had been thinking about making my own or Porting XUnit, but now I don’t have to.  I’ve grown to like the minimalistic XUnit interface, and I feel blind without NCover, but this will do for now.

Source code: DamonPayne.AGT[8].zip (622.87 KB)



Sunday, September 21, 2008 6:32:39 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, September 20, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible design-time environment similar to what we have in Visual Studio 2008.  This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Part 8 in a 50 part series begins...

Drag and Drop

It’s time to try dragging something out of the Toolbox and onto the DesignSurface.

We start dragging by wiring up events inside the ToolboxCategoryControl.  We’ve already established a mechanism for making sure only one ToolboxItem is ever selected, and that the ToolboxView owns the ToolboxCategoryControl.  We define a normal local dragstart event:

        void cat_DragStart(object sender, EventArgs e)

        {

            ToolboxItem tbi = SelectedItem;//Will already be populated from event wireup

            DragDropManager.BeginDrag(tbi);

        }

I have implemented the cleverly named DefaultDragDropManager in the DamonPayne.AGT.Design.Services namespace to handle the task.  The first thing DDDM does is obtain a drag-time representation of the Control visual.  This is one of the places where we start diverging more and more from how VS2008 works and looks today. While I’m not ready for the Visual Refactoring stage yet, we can clearly do better than a tiny mouse cursor with a “+” next to it.  This is what IDragTypeCreator is for: to provide a pluggable mechanism for building a better representation of what you’re dragging around than a mouse cursor.  I created a special DragContainer control for this purpose in DamonPayne.AGT.Design.Controls.  Here is the entire DefaultDragTypeCreator.CreateDragRepresentation method:

        public Control CreateDragRepresentation(Type t)

        {

            //Default behavior:

            DragContainer dc = new DragContainer();

            Control c = (Control)Activator.CreateInstance(t);

            //Thanks to http://www.jeffblankenburg.com/2008/04/how-about-some-code-simple-resizing-in.html for scaling code

            //TODO, extension method for uniform scale size?

            double originaltWidth = c.Width;

            double originalHeight = c.Height;

            double uniformScaleAmount = Math.Min(MAX_DIMENSION / originaltWidth, MAX_DIMENSION / originalHeight);

            ScaleTransform st = new ScaleTransform();

            st.ScaleX = uniformScaleAmount;

            st.ScaleY = uniformScaleAmount;

            c.RenderTransform = st;

            c.InvalidateMeasure();           

            c.UpdateLayout();

           

            //TODO: why couldn't I force this to recalc size here after setting render transform?

            double estimatedNewWidth = c.Width * uniformScaleAmount;

            double estimatedNewHeight = c.Height * uniformScaleAmount;

            double left = (dc.Width / 2.0D) - (estimatedNewWidth / 2.0D);

            double top = (dc.Height / 2.0D) - (estimatedNewHeight / 2.0D);

            c.SetValue(Canvas.LeftProperty, left);

            c.SetValue(Canvas.TopProperty, top);

            dc.LayoutRoot.Children.Add(c);

            dc.Opacity = .65D;

            dc.LayoutRoot.Opacity = .65D;

           

            return dc;

        }

I am basically creating an instance of whatever Type I was given, which ultimately came from ToolboxItem.Type.  Then I scale the instance down to where it will fit in my DragContainer and return the DragContainer.  With this in hand, DefaultDragDropManager wires up the mouse events for dragging around: basically when mouse left button goes up we do a hit check to see if there is an IDropTarget registered with us that would be under the current mouse position.  With the events set, we add the DragContainer control to the root visual of the Silverlight application.

Design Surface

The next thing I need to actually implement is the DesignSurface control, implementing IDropTarget.   This needs to be added into the IRegionManager way back when the ToolboxView and MessageConsole are created.  I’ve resized the whole Page such that I can fit a 480x640 gray DesignSurface in there.  You can now see me take my drag-time couch representation over to the design surface:

As soon as I got into developing the drop part, I realized I was in the Silverlight world, thinking like a WinForms developer.  Silverlight has built in hit test code already and I don’t need to do anything with Bounds.  The IDropTarget interface is thefore modified to use UIElement.HitTest(Point), so the EndDrag method can now do this:

        public virtual void EndDrag(MouseButtonEventArgs e)

        {

            RegionManager.TopLevelContainer.Children.Remove(_dragRepresentation);

            _dragRepresentation = null;

           

            foreach (IDropTarget target in _dropTargets)

            {

                if (target.IsHitTestVisible)

                {

                    IEnumerable<UIElement> elements = target.HitTest(_mousePos);

                    if (elements.GetEnumerator().MoveNext())//hit test succeed

                    {

                        IDesignableControl ctrl = DesignCreator.CreateInstance(_draggingType);

                        target.OnDrop(ctrl);

                    }

                }

            }

_draggingType = null;

        }

As soon as we enter OnDrop, the design time representation is worthless and we throw it away.  We’ll either be building the real control the surface or simply cleaning up.  I believe in the last article I described the interaction as the DesignSurface calling the creation method from OnDrop, but it makes more sense to put it here now.    For now, the IDesignTypeCreator simply instantiates the appropriate Type.  DesignSurface.OnDrop is incredibly simple for now:

        public void OnDrop(IDesignableControl dc)

        {

            dc.Visual.SetValue(Canvas.LeftProperty, _localMousePos.X);

            dc.Visual.SetValue(Canvas.TopProperty, _localMousePos.Y);

            LayoutRoot.Children.Add(dc.Visual);

        }

Success!  Here’s the very nice looking purple couch on the design surface.

Clearly there is tons of work to be done still, but I was shocked when I actually ran metrics: this just a little over 500 lines of code so far!

Source code: DamonPayne.AGT[7].zip (613.16 KB)



Saturday, September 20, 2008 1:06:22 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 18, 2008

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible design-time environment similar to what we have in Visual Studio 2008.  This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Designer surface interactions

My goal now is to actually start thinking about creating and designing things.  The preferred means of using this is as follows:

1.       From the toolbox I start dragging something out towards the Great Wide Open.

2.       Somehow visually indicate that I am dragging something.

3.       When I let go, see where I have dropped what I was dragging.

4.       If what I dropped upon was something that cares about being dropped on, do something useful like create a design-time representation of the thinger.

Some “improved” traffic patterns downtown where I work has left me with a lot of time to think about design interactions on my way home every day.  As I’m coming to expect, every single thing related to Drag ‘n drop in WPF or WinForms is not in Silverlight, but we can start defining some constructs of our own.  I’m adding a Design Solution Folder, within which will be a StarUML project.  Sometimes it’s better to explain using pictures.

  

1.       IToolboxService should use IDragDropManager to indicate that Drag operation is beginning.

2.       IDragDropManager will query the IToolboxService to determine what is the type of the dragging item.

3.       IDragDropManager will use IDragTypeCreator to build some type of visual representation to indicate where the dragging item is.  It will attach some events to this Control and place it as a child of the RootVisal of the IRgeionManager, in the front of the Z-order.

4.       The end of a drag/drop will be determined by the events attached to the Control, such as Left mouse button up.

5.       IDragDropManager will query all the IDropTarget instances registered with it.  If the Location of the where the dragging Control was dropped falls within the Bounds of one, it will call that instances OnDrop event with the original ToolboxItem.  This allows the IDropTarget to do whatever it wants using the original information.  Otherwise, the drag representation will be destroyed by IDragDropManager.

6.       In our case, if we successfully drop on top of the visual representation of a DesignSurface instance, DesignSurface will use IDesignTypeCreator to create the final design-time representation of the IDesignableControl.  This allows different visuals and behaviors to be attached such as adorners for resizing and registration with various other design-time services.

 

I am nearly certain I am going to have to change RootVisual of IRegionManager to be a Panel rather than UIElement.  UIElement has no “children” collection for me to use for my drag-representation.  Based on some things I want to support later (alignment snap lines, possible extra adorners) the DesignSurface is ultimately going to have to be a base type or implement some kind of interface with some kind of collection of “filters” or IDesignSurfaceBehavior implementations.

The source code as of the end of this article contains stubbed out unfunctional versions of the interfaces mentioned here. In the next article, we’ll actually try to drag/drop around a purple couch.  After that we’ll spend some time doing code refactoring (the TODO are building up) and some visual refactoring before moving on to more complex interactions.

Source code: DamonPayne.AGT[6].zip (598.45 KB)



Thursday, September 18, 2008 7:43:00 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

The RSS aggregators chopped off AGT[4], probably for being too long.  Still, you'll want to read #4 since we make huge progress in that article.  AGT[5] deals with the wild tangent involving dynamic proxy generation with Reflection Emit.

AGT[4] http://www.damonpayne.com/2008/09/18/RunTimeIsDesignTimeForAGT4.aspx

AGT[5] http://www.damonpayne.com/2008/09/18/RunTimeIsDesignTimeForAGT5.aspx



Thursday, September 18, 2008 5:42:43 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible design-time environment similar to what we have in Visual Studio 2008.  This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Tangent: Dynamic proxy generation in Silverlight using Reflection Emit

In the last article I made mention of a tangent, an evil waste of time.  If a component asks for an IService implementation that cannot be found, I started out throwing an exception saying so.  Then I found a situation where I wanted to allow a Service to be registered after it was needed, and only have an exception be thrown if the missing service was accesses before it could be somehow injected later.  This is the solution.

While I’m not very interested in Dynamic Languages right now, I am reaping the benefits of Microsoft’s attention to them.  Without consideration for the DLR in Silverlight, I doubt they would have included such a complete Reflection Emit implementation.

ServiceManager

We started out with a ServiceManager.Resovle method that looked like this:

        public static object Resolve(Type t)

        {

            object svc = null;

            if (_services.ContainsKey(t))

            {

                svc = _services[t];

            }

            else

            {

                throw new NotSupportedException(string.Format("A provider for {0} was not found", t));

            }

            return svc;

        }

We need to replace what’s in the else clause and make ServiceManager and ComponentBuilder a little smarter.  The first step is to create a way to keep track of the situation inside ComponentBuilder:

        /// <summary>

        /// Key=IService type, value=list of objects waiting on that IService

        /// </summary>

        private static Dictionary<Type, List<object>> _lateBinding;

        static ComponentBuilder()

        {

            _lateBinding = new Dictionary<Type, List<object>>();

        }

                {

                    object svc = null;

                    try

                    {

                        svc = ServiceManager.Resolve(propType);

                    }

                    catch (NoImplementationException)//TODO: fix this so an exception is not thrown?

                    {

                        svc = SetupLateBinding(propType, component);

                    }

        private static object SetupLateBinding(Type interfaceType, object client)

        {

            object svc = InterfaceMocker.GenerateProxy(interfaceType);

 

            if (!LateBinding.ContainsKey(interfaceType))

            {

                LateBinding.Add(interfaceType, new List<object>());

            }

 

            LateBinding[interfaceType].Add(client);

 

            return svc;

        }

We change the ServiceManager to throw NoImplementationException instead of NotSupportedException.  When ServiceManager is given something new to Manage now, we check to see if anyone out there was waiting on a service of this type:

        private static void CheckLateBinding(Type interfaceType, object provider)

        {

            if (ComponentBuilder.LateBinding.ContainsKey(interfaceType))

            {

                List<object> clients = ComponentBuilder.LateBinding[interfaceType];

                foreach (object c in clients)

                {

                    var propQuery = from p in c.GetType().GetProperties().AsQueryable<PropertyInfo>()

                                    where p.PropertyType == interfaceType

                                    select p;

                    foreach (PropertyInfo propInfo in propQuery)

                    {

                        propInfo.SetValue(c, provider, null);

                    }

                }

                ComponentBuilder.LateBinding.Remove(interfaceType);

            }

        }

 

 

TypeMocker

The magic of all the code shown above is contained in TypeMocker.  Our goal is this: given an Interface type we cannot find an implementation for, make up a very simple placeholder one which could potentially do something useful if we call methods on it.  Unfortunately the most useful things raise more issues than they solve in .NET:

·         I don’t have pointers here, so I can’t very well try to replace “this”, nor get at the enclosing object instance to do any sneaky replacement.

·         If I wanted to do a delegation model, where the proxy ultimately just obtained a ‘normal’ instance and delegated to that via inheritance or something, those methods would need to be virtual and I don’t want to force that on users of this library, especially myself.

The first thing we need to be able to do is create the assembly. You may recognize the name from the Badge of Honor article.

        private static ModuleBuilder GetDynamicModuleBuilder()

        {

            if (null == _dynamicModuleBuilder)

            {

                AppDomain currentDomain = AppDomain.CurrentDomain;

                AssemblyName proxyName = new AssemblyName("DamonPayne.IoC.TempProxy");

                AssemblyBuilder aBuilder = currentDomain.DefineDynamicAssembly(proxyName, AssemblyBuilderAccess.Run);

                //

                ModuleBuilder module = aBuilder.DefineDynamicModule(proxyName.Name);

                _dynamicProxyAssembly = aBuilder;

                _dynamicModuleBuilder = module;

            }

 

            return _dynamicModuleBuilder;

        }

 

        private static AssemblyBuilder _dynamicProxyAssembly;

        private static ModuleBuilder _dynamicModuleBuilder;

Now we can work on dynamically creating a class that implements an interface in GenerateProxy:

        public static object GenerateProxy(Type t)

        {

            if(!t.IsInterface)

            {

                throw new ArgumentException(t + " Is not an interface");

            }

            //Useful:

            //http://msdn.microsoft.com/en-us/library/3y322t50(VS.95).aspx

            object o = null;

            ModuleBuilder module = GetDynamicModuleBuilder();

            //

            TypeBuilder typeBuilder = module.DefineType(t.Name+"TempProxy",

                TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.Class,typeof(object) );

            typeBuilder.AddInterfaceImplementation(t);

We create a class that extends Object and implements interface “t”.  Because we are writing IL ourselves, lots of things that would ordinarily be done by the compiler have to be taken into consideration.  This includes calling the base class constructor from within our own:

            ConstructorBuilder conBuilder =

                typeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.SpecialName, CallingConventions.Standard, Type.EmptyTypes);//TODO: use Type.EmptyTypes elsewhere!

            //Define the reflection ConstructorInfor for System.Object

            ConstructorInfo conObj = typeof(object).GetConstructor(new Type[0]);

 

            //call constructor of base object

            ILGenerator il = conBuilder.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);

            il.Emit(OpCodes.Call, conObj);

            il.Emit(OpCodes.Ret);

This next bit is tedious but easy to understand once you know what you’re trying to do.  Create a method on my new type for each interface method I need to implement.  The implementation currently just throws an exception saying that our attempt to allow friendly late binding failed:

            List<MethodInfo> interfaceMethods = new List<MethodInfo>();

            interfaceMethods.AddRange(t.GetMethods());

 

            Type[] extraInterfaces = t.GetInterfaces();

            foreach (Type extraIface in extraInterfaces)

            {

                interfaceMethods.AddRange(extraIface.GetMethods());

            }

 

            foreach (MethodInfo method in interfaceMethods)

            {

                ParameterInfo[] mParams = method.GetParameters();

                Type[] paramTypes = new Type[mParams.Length];

                for(int i = 0; i < mParams.Length; ++i)

                {

                    paramTypes[i] = mParams[i].ParameterType;

                }

 

                MethodBuilder methodBuilder =

                    typeBuilder.DefineMethod(method.Name,

                    MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.SpecialName, method.ReturnType, paramTypes);

               

                ILGenerator ilGen = methodBuilder.GetILGenerator();

                if (method.Name.Equals("Startup") || method.Name.Equals("Shutdown")) //TODO: dehackify this

                {

                    ilGen.Emit(OpCodes.Ret);

                }

                else

                {

                    ilGen.ThrowException(typeof(NoImplementationException));

                }               

            }

 

            Type finalType = typeBuilder.CreateType();

 

            o = Activator.CreateInstance(finalType);//TODO: replace other default constructor code with Activator

 

            return o;

There’s probably some work to do here to make sure attempts at creating  a proxy for the same type more than once are handled and so forth, but I’ll get to that when I decide on a unit test platform.  For now, its solving my late order-of-creation problems and would event support a circular dependency should one arrive.  My region manager/Page startup now goes through this sequence:

1.       We ask ServiceManager to handle Page, which is an IRegionManager.

2.       Page contains a RootPresenter, RootPresenter is created and needs an IToolboxService.

3.       IToolboxService is not found, but we get a dynamically created IToolboxServiceTempProxy instead.

4.       The UserControl_Loaded event of Page is called, which creates the toolbox service.

5.       Page gets a real IToolboxService implementation and everyone is happy.

At the end of this article, I am clearly not happy with the relationship between ComponentBuilder and ServiceManager.  I’m going to have to fix that, but first I want to get some more work done on my actual problem domain.

 

The source code is the same as what I posted for AGT[4].



Thursday, September 18, 2008 3:28:26 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

The AGT (Argentum Tela) series of articles is an effort to do two things.  Usually an idea is presented only in its finished form.  The first goal is to do some Reality Blogging, to show an idea evolve over time without pulling any punches.  The second goal, and the example vehicle for the evolution aspect, is an extensible design-time environment similar to what we have in Visual Studio 2008.  This type of application has all sorts of interesting uses.  My example is a Home Theater layout tool.  Read the entire saga: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Toolbox Service UI

It is now time to do some slightly more meaningful XAML work and create the visual representation of the toolbox service: this is where we’ll stow the designable components and drag them off onto the yet-to-be-created designer surface.  I am NOT going to worry about making it look snappy until later.

In order to test the ToolboxView, I have created the first designable item.  It is a big purple “Couch”.  I must stress to you that it does look like a couch.  It’s purple and has cushions, as anyone can clearly see.

 

What did I tell you?  Couchtastic.  I’m working on getting a better XAML couch or finding some patience to draw a better one.  This will be good enough to test with.

Looking back at the previous article, I chose to support a categorized toolbox like VS2008.  Therefore I’m going to make another UserControl called ToolboxCategory which is simply a heading stating the category name and a ListBox full of some representation of the ToolboxItems.  Simple XAML for the Category to start with:

<UserControl x:Class="DamonPayne.HTLayout.Controls.ToolboxCategoryControl"

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

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

    Width="205" Height="Auto">

    <Grid x:Name="LayoutRoot" Background="White">

        <Grid.RowDefinitions>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>

        <TextBlock x:Name="_categoryHeader" Grid.Row="0">Category Header</TextBlock>

        <ListBox x:Name="_itemLst" Grid.Row="1" DisplayMemberPath="Name">           

        </ListBox>

    </Grid>

</UserControl>

I’ll add some public properties to ToolboxCategoryControl to communicate with its parent.  I’m not ready to rewrite Silverlight data binding so I’ll have to make some concessions.  I’ll go ahead and start writing the little code I need to populate the IToolboxService.

Create the ToolboxView and hand it over to the region manager as soon as the Page (our entry point UserControl) is loaded:

            ToolboxView tbView = ComponentBuilder.Create<ToolboxView>();

            mgr.AddView(tbView, "Toolbox");

Create a RootDesignerPresenter to handle logic for the DamonPayne.HTLayout.Page:

        [Presenter()]

        public RootDesignerPresenter Presenter { get; set; }

             Presenter.InitializeDesignableControls(); …

When I run this code I realize I made a mistake earlier.  The whole point of making the ComponentBuilder helper methods internal and not private was to use them to wire-up dependencies from service types as I manage them in ServiceManager.  Adding these calls to ServiceManager.CreateDefaultInstance fixes the issue and I’ve added another todo item to take a look at this after I have some more real code.   

                //TODO: maybe use the ComponentBuilder to create the damn thing in the first place

                ComponentBuilder.ResolveServiceDependencies(o);

                ComponentBuilder.BuildPresenters(o);

And another mistake pops up when I run this code. Page is created on AppStartup.  Page depends on RootDesignerPresenter, which depends on IToolboxService.  The IToolboxSerivce implementation is also our ToolboxView UserControl, which does not get created until the Page.UserControl_Loaded event completes.  So while we are wiring up the dependencies for Page, we get “A provider for DamonPayne.AGT.Design.Contracts.IToolboxService was not found.”  Now the previous design decisions come back to haunt us again and I’m facing another round of decisions.

1.       I could build the UI components in the proper order in Application_Startup.  This requires me, the developer, to be smart about what depends on what.  In fact, this also begs the question of what to do later if I find that there is a circular dependency between services.

2.       Return to the idea of making a class that implements IToolboxService and interacts with the visual representation using this other mechanism. 

3.       Create a mechanism for late-binding IService implementations.  By this I mean, rather than throw an exception from ServiceManager.Resolve() if an implementation cannot be found, store the fact that I’m missing an implementation for a certain interface on a certain type and inject this IService later if it becomes available.

4.       Make ServiceManager smarter.  Suppose we gave ServiceManager 100 types to manage at once, and some of those had dependencies on each other.  We could make ServiceManager either build a dependency tree, or even easier, take multiple passes over the collection of 100 types in a sort of poor-man’s (lame programmer’s) tree-flattening.

 

#1 would get me on my way the fastest, and also seems lame.  If I have circular dependencies, #1 will never work, although circular dependencies should be avoided.  I may also find myself spending a lot of time later keeping track of dependencies in my head and change the order of type registration around.

#2 will almost certainly just move the problem elsewhere, unless this new magical class does not have its visual representation provided to it as an automatic service.  This may be the cleanest option.

#4 might be useful on its own, but would also involve re-thinking how I create and manage Views and such.  I’m going to reject this one for now.

#3 has some appeal.  This would even allow for (accursed) circular dependencies.  The first drawback that comes to mind is that throwing an exception right away gives an immediate and unambiguous message that something is wrong and what that something is.  Attempting to use an IService that is waiting around for someone to create it by registering it with ServiceManager or ComponentBuidler would just result in a null reference – a ubiquitous and annoying exception.

There is an additional, and totally evil, option I could tack on to #3.  Silverlight is a partial implementation of the base class libraries we are used to, like the Compact Framework.  Because of this, one always has to go back and inspect class availability using Intellisense or the reference documentation.  Probably because of Silverlight’s dynamic language support – a fairly complete System.Reflection.Emit implementation is present.  In addition to remembering that I’m “waiting around for an ISuck implementation”, I could dynamically create a class that implements ISuck and throws an exception saying “Sorry, this is a placeholder and we never found an implementation for you” in case any methods are called before the implementation can be found. 

Using the great sanity check mechanism known as “Who’s on MSN Messenger” I happened to find a respectable software architect online to bounce this notion off of.  The conversation went something like this:

Damon: <explains situation and #3 solution>
Damon: So, is this overkill just to keep from throwing a null reference?

OtherDude: Uh, yeah, way overkill.  Save that for when your whole application works and you want to start gold-plating.  Version 3 or something.

Unfortunately I was 90% done with the reflection emit idea before this dissenting opinion arrived.  Honestly this was a ludicrous tangent but is also fun.  I will cover the solution in the next article.  Suffice to say that we are supporting Clever Late Binding for IService implementations and we can continue with the Toolbox Service.

The RootDesignerPresenter contains logic, such as “What am I putting in this toolbox?” For now I’ll only add one thing and be sure this all works.

        public void InitializeDesignableControls()

        {

            ToolboxItem couchItem = new ToolboxItem("Purple Couch", "This is clearly a couch", typeof(Couch));

            Toolbox.AddItem(couchItem, "Furniture");

        }

Making this work is painful because Silverlight does not support RelativeSource for data binding.  I can’t use a property on “this” for setting the Category Name TextBlock.  I’m now actually terrified of what I’m going to discover for data binding in Silverlight, but for now I’ll just make the property set the value. 

Of course the very next thing I try to do exposes another data binding shortcoming.  List<T> does not implement INotifyPropertyChange so that if I add a ToolBoxItem to a List<ToolBoxItem> which service as ItemsSource the GUI does not update itself.   I have three primary choices here.  I can build a special ScreenModel object for this screen which contains a List property I can fire INotifyPropertyChange for, I can try to implement a custom List<T> that does what I want, or I can mess with everything completely manually.  For now, I will use a ViewModel, which also erases my previous manual setting of the Category Name.  It’s worth reproducing the whole View Model here to point out how it’s implemented for automatic data binding goodness.

using System.Collections.ObjectModel;

using System.ComponentModel;

using DamonPayne.AGT.Design.Types;

 

namespace DamonPayne.HTLayout.ViewModels

{

    public class ToolboxCategoryModel : INotifyPropertyChanged

    {

        public ToolboxCategoryModel()

        {

            ToolboxItems = new ObservableCollection<ToolboxItem>();

        }

 

        private string _CategoryName;

        public string CategoryName

        {

            get { return _CategoryName; }

            set

            {

                _CategoryName = value;

                OnPropertyChanged("CategoryName");

            }

        }

 

        private ObservableCollection<ToolboxItem> _ToolboxItems;

        public ObservableCollection<ToolboxItem> ToolboxItems

        {

            get { return _ToolboxItems; }

            set

            {

                _ToolboxItems = value;

                OnPropertyChanged("ToolboxItems");

            }

        }

 

        public event PropertyChangedEventHandler PropertyChanged;

 

        public void OnPropertyChanged(string pname)

        {

            if (null != PropertyChanged)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(pname));

            }

        }

    }

}

 INotifyPropertyChange does not work for collection types.  INotifyCollectionChanged  does not seem to be used by data binding if I put it on my ToolboxCategoryViewModel.  The answer is System.Collections.ObjectModel.ObservableCollection<T>, which implements INotifyCollectionChanged  in the way the data binding code in Silverlight is expecting .  I’ve made myself some code snippets for the INotifyPropertyChanged code since I suspect I’ll need them later.

For the basic implementation:

<?xml version="1.0" encoding="utf-8"?>

<CodeSnippets

    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

  <CodeSnippet Format="1.0.0">

    <Header>

      <Title>OnPropertyChanged</Title>

      <Author>DamonPayne.com</Author>

      <Description>Insert a default OnPropertyChanged method and INotifyPropertyChanged event</Description>

      <Shortcut>OnPropertyChanged</Shortcut>

    </Header>

    <Snippet>

      <Code Language="CSharp">

        <![CDATA[

        public event PropertyChangedEventHandler PropertyChanged;       

       

        protected void OnPropertyChanged(string pname)

        {

            if (null != PropertyChanged)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(pname));

            }

        }       

        ]]>

      </Code>

    </Snippet>

  </CodeSnippet>

</CodeSnippets>

 

Per property:

<?xml version="1.0" encoding="utf-8" ?>

<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">

    <CodeSnippet Format="1.0.0">

        <Header>

            <Title>INotifyPropertyChanged property</Title>

            <Shortcut>inotifyprop</Shortcut>

            <Description>INotifyPropertyChanged prop, assumes OnPropertyChanged</Description>

            <Author>DamonPayne.com</Author>

            <SnippetTypes>

                <SnippetType>Expansion</SnippetType>

            </SnippetTypes>

        </Header>

        <Snippet>

            <Declarations>

                <Literal>

                    <ID>type</ID>

                    <ToolTip>Property Type</ToolTip>

                    <Default>string</Default>

                </Literal>

                <Literal>

                    <ID>property</ID>

                    <ToolTip>Property Name</ToolTip>

                    <Default>BindingProperty</Default>

                </Literal>

            </Declarations>

            <Code Language="csharp">

                <![CDATA[

 

private $type$ _$property$;

public $type$ $property$

{

    get { return _$property$; }

            set

            {

                  _$property$ = value;

      OnPropertyChanged("$property$");

            }

}

$end$]]>

            </Code>

        </Snippet>

    </CodeSnippet>

</CodeSnippets>

 

Next I’ll add some Item selection code using my event aggregator.  I’m going to define a generic SelectedDataChangedEvent:

    public class SelectedDataChangedEvent<T>:AggregateEvent<T>

    {

        public T Payload { get; set; }

    }

Now my constructor for the View Model looks like this:

        public ToolboxCategoryModel()

        {

            ToolboxItems = new ObservableCollection<ToolboxItem>();

            _selectionEvent = EventAggregator.Get<SelectedDataChangedEvent<ToolboxItem>, ToolboxItem>();

            _selectionEvent.Subscribe(item => { SelectedToolboxItem = null; }, item => !ToolboxItems.Contains(item));

        }

 

        private SelectedDataChangedEvent<ToolboxItem> _selectionEvent;

Behold the simple power of the event filters.  These two lambdas just say “If anyone anywhere else selects a toolbox item that is not part of my collection, I’ll be a nice citizen and clear my own selection.”  The selected item now participates in data binding AND event aggregation and it feels cleaner than I expected:

SelectedItem="{Binding Path=SelectedToolboxItem, Mode=TwoWay}"

        private ToolboxItem _SelectedToolboxItem;

        public ToolboxItem SelectedToolboxItem

        {

            get { return _SelectedToolboxItem; }

            set

            {

                _SelectedToolboxItem = value;

                OnPropertyChanged("SelectedToolboxItem");

                if (null != value)

                {

                    _selectionEvent.Raise(value);

                }

            }

        }

Back in the real IToolboxService implementation, we need to subscribe to this event too.  And now we have a toolbox service with gui!

 

It doesn’t look like much, but in the future there will be some “visual refactoring” going on.  I’ll sure miss my awesome purple couch though.

Conclusion

This step ended up being very long since there were several rabbit holes to go down.  We’ve created a Toolbox service, proven the EventAggregator is going to work, learned some things about Silverlight data binding I didn’t know before, and introduced the concept of the View Model into our lexicon.  In the next few steps, things will get really interesting!

Source code: DamonPayne.AGT[4].zip (571.61 KB)



Thursday, September 18, 2008 3:26:29 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, September 16, 2008

You simply know you're doing good, important, awesome work when you are able to get this error at runtime:

An exception of type 'System.Security.VerificationException' occurred in DamonPayne.IoC.TempProxy but was not handled in user code

Additional information: Operation could destabilize the runtime.

The Type name "DamonPayne.IoC.TempProxy" is wrong, and doesn't exist, which just adds to the fun. This will factor into the AGT series of articles, but I took a brief break to share this badge of honor.  In the age of awesome search engines, a developer can often learn how to quickly do a search for their particular error type or error message or get lucky based on some aspect of their exception stack trace.  Sometimes, very rarely (rarely unless you are Dan) you will have an error so specific that no one has blogged about it, or documented it, or asked about it in newsgroups.  The first reaction to this situation is typically panic or disgust; "crap I'm in uncharted territory" or "I can't believe no one else has tried this".  Sometimes these feelings are followed by Pride.  In a time of rising water level, more and more abstractions between the programmer and the metal, there is a certain appeal to doing something that was clearly not intended by the developers of the frameworks you are consuming.  At the very least, you now know that you are down in the bowels of The Machine, far below the safety nets installed to save Mort from himself.



Monday, September 15, 2008 11:06:11 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, September 15, 2008

If you’re just jumping in, you may want to start from the beginning: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Beginning the Designer

In case you’re not pouring over the source code with interest and reverence, let’s take a quick snapshot of the structure that is emerging:

There’s very little in the IoC or HTLayout projects so far, but it seems very clean up to this point.  I have also done nearly nothing related to my core problem of a Design Time environment for Silverlight: the Design project stands empty.  It seems sensible enough to work from left to right for the time being, so let’s begin with the Toolbox. 

Designable

The next step is to create an abstraction for what we are going to be working with.  In the VS2008 design time environment the coin of the realm is the System.ComponentModel.Component.  In many ways I didn’t like this since one is nearly always casting Component to Control.  Creating an interface that gives us a grammar for something which is “designable” and also has a visual representation will be a better place to start.

namespace DamonPayne.AGT.Design

{

    public interface IDesignableControl

    {

        /// <summary>

        /// Visual representation of this IDesignableControl

        /// </summary>

        Type VisualType { get; }

 

        /// <summary>

        ///

        /// </summary>

        bool Scalable { get; }

 

        /// <summary>

        /// Should the designer allow transformations such as rotation to be applied?

        /// </summary>

        bool Transformable { get; }

 

        string Name { get; set; }

    }

}

That’s all I’ve got for now.  Clearly I’ve thought this through…

Toolbox Service

A toolbox is a thing that displays a list of things you can drag out into another thing.  It is a thing as well as a meta-thing.  Beginning in Visual Studio 2005 we had the notion of a categorized toolbox.  I like that, so the next step is to decide on the starting point for a Toolbox service.  Keeping with the Microsoft design for now, I create a ToolboxItem.

namespace DamonPayne.AGT.Design.Types

{

    public class ToolboxItem

    {

        public ToolboxItem():this("Unknown", "No description",null)

        {

        }

 

        public ToolboxItem(string name, string desc, Type type)

        {

            Name = name;

            Description = desc;

            Type = type;

        }

 

 

        public string Name { get; set; }

        public string Description { get; set; }

        public Type Type { get; set; }

    }

}

The IToolboxService is straightforward.

namespace DamonPayne.AGT.Design.Contracts

{

    public interface IToolboxService : IService

    {

        void AddItem(ToolboxItem item);

        void AddItem(ToolboxItem item, string category);

        ToolboxItem SelectedItem { get; }

        void RemoveItem(ToolboxItem item);

    }

}

That will serve for now.  Before I get into creating some funky purple couches and speakers in Expression Blend, I need to make sure my framework supports my next intended action.

    public partial class ToolboxView : UserControl, IView, IToolboxService

It makes a lot of sense for the visual toolbox UserControl to implement the IToolboxService interface.  Who better?  Now I need to take a look at my framework already.  Things that I need to create as top level objects go through the ControlBuilder.  Things that need to provide service implementations to other components are created when their Type is registered with the ServiceManager.  I’m trying to have it both ways and I can’t without doing more work.  Since I envision the same situation for the designer surface and property grid later on this deserves some thought.

1.       I could create a non-visual toolbox class that knows about the ToolboxView and have this class implement the IToolboxService instead.  The ToolboxView would have to provide public methods for all the appropriate operations.

2.       In addition to #1, I could change ToolboxView to have a “Visual” property that could be set at a later time.

3.       I could change ServiceManager such that the ToolboxView (while implementing IToolboxService) is actually instantiated up front just like other service providers and somehow requested.

4.       I could strengthen the loving relationship between ComponentBuilder and ServiceManager.

Recall the public interface to ComponentBuilder:

public static T Create<T>() where T :new ()

I could fairly easily detect here that I’ve been asked to create something which is potentially both a service provider and service consumer and pass it off to ServiceManager after fully building it.  Unless I receive one metric ton of hatemail, I will take this approach for now.  ComponentBuilder can call this entirely new ServiceManager.ManageInstance method:

        public static void ManageInstance(object provider)

        {

            Type baseServiceType = typeof(IService);

            Type t = provider.GetType();

            Type[] interfaces = t.GetInterfaces();

            foreach (Type iface in interfaces)

            {

                if (iface.InterfaceExtends(baseServiceType))

                {

                    _services.Add(iface, provider);

                }

            }

        }

The main issue that I can foresee is getting into trouble with multiple instances of an IService being provided by different Types.  If this situation arises, some form of discriminator will need to be introduced.  For now, though, this is a good stopping point.  In the next article we can begin the visual implementation of the ToolboxView.

Source code: DamonPayne.AGT[3].zip (672.51 KB)



Monday, September 15, 2008 7:30:55 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Some news aggregators (Google reader) like to just ignore articles from DasBlog if they get too long, or perhaps it doens't like the special formatting HTML I get when copy/pasting out of Word.  At any rate, if you are following the AGT series, please check out

AGT[1] http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT1.aspx (Composite UI and modules)

and

AGT[2] http://www.damonpayne.com/2008/09/15/RunTimeIsDesignTimeForAGT2.aspx (Service wire-up, presenters, and Events)

I will keep my eye on Google Reader and be sure to double post.  I think I've been singled out for this behavior for my Break Up Google article.



Monday, September 15, 2008 8:42:22 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, September 14, 2008

If you are just joining, you might want to start from the beginning: http://www.damonpayne.com/2008/09/14/RunTimeIsDesignTimeForAGT0.aspx

Service Wire-up, Presenters, and Events

As I wrapped up the last article I found that I needed to determine a mechanism for providing IService implementations to Components that need them, and that it would be nice to have this happen in some automatic repeatable fashion.  As for providing IService implementations, there are four ways (four that come to mind right now anyway) to do this, one of which I have already shown:

1.       Explicitly: ISuck is = ServiceManager.Resolve<ISuck>();

2.       Implicit magic: public ISuck MySuck{get;set;} //set by some magic

3.       Via constructor: public MyServicedComponent(ISuck defaultSuck){…} //possibly also set by magic

4.       Via a Serviced Component interface: perhaps something like this, coupled with a registration mechanism:

    public interface IServicedComponent

    {

        IService[] GetDependencies();

        void SetDependency(Type serviceType, IService impl);

    }

In terms of discoverability of what is going on, #4 wins.  Back in my original design goals I stated that I wanted things to feel like Serviced Components.  An interface like this, which we could build on, would establish an unambiguous set of expectations and behaviors.  When it gets down to the other design consideration of “How do I want to code?”, though, I’m not very in love with #4.  #1 is safe but puts any future lifecycle management we may want to do out of reach most likely.  To support #2 or #3, I am going to need control over when most important objects are created.  It seems that going with #3 would make the various Reflection code that I have and expect I’ll have later a bit more messy.  As much as it