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
2007 Microsoft MVP - Solution Architecture
 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

Hey, I got mentioned on the world famous Thirsty Developer podcast.



Monday, October 13, 2008 8:44:32 AM (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

I should have done this a long time ago since Google analytics does not track RSS subscribers.

Please update your syndication links to use feedburner: http://feeds.feedburner.com/damonpayne



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

I have the dubious honor of being the subject of Matt Terski's last blog post from quite some time ago, but The Terski is blogging again, this time at The Use Case Blog - sponsored by his company Serlio Software.  While the articles mostly show their worth all by themselves, keep in mind that Terski and his partners are no strangers to the Tool space, having previously been at a little company you may have heard of - Rational.

I definately agree with the latest post: http://blog.casecomplete.com/post.aspx?id=2c94856f-2e99-464a-86ba-c9184c393fd3

There is a consulting company here in Milwaukee, one that I generally like, who is going after the "Application Lifecycle" segment fairly hard.  Their goal is to use Team System to help clients tie every line of code back to a business goal.  While this may seem admirable on the surface, I Recoil in Horror from this type of thinking.  What benefit does a business think it will get from doing this?  Is squashing creativity and necessary risk taking so important?  There is a principle in Physics that states the act of measuring something alters the results obtained from the measurement.  Most business people today in the upper echelons of a publicly traded company would be happy to tell you the detrimental effects that Sarbanes-Oxley has on their day to day operations, so why impose something even more draconian on software development?

The bottom line is that many, many features of popular software development or requirements tools are much better at selling licenses than they are at solving any real problem.



Wednesday, October 08, 2008 12:29:33 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

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
My friends, family, co-workers, and Twitter followers know that I am a huge fan of red wine.  When I recently tabulated and estimated what I've spent on wine to drink, wine to store, and wine to gift in the past 12 months I was very nearly ashamed.  Nearly, but not quite!  As it turns out, though, it's all for the good.  Here's yet another study linking the antioxidants in red wine to some sort of cancer prevention:

http://tinyurl.com/44aoc3

Now if only the price of Bourgogne and Chateauneuf du Pape would stop going up.



Tuesday, October 07, 2008 9:38:02 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

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 s