private void DragLeft( double scale, DesignerItem item, DesignerCanvas canvas )
        {
            var groupItems = canvas.SelectionService.GetGroupMembers( canvas, item ).Cast<DesignerItem>();

            double groupLeft = Canvas.GetLeft( item ) + item.Width;
            foreach ( var groupItem in groupItems )
            {
                double groupItemLeft = Canvas.GetLeft( groupItem );
                double delta = (groupLeft - groupItemLeft) * (scale - 1);
                Canvas.SetLeft( groupItem, groupItemLeft - delta );
                groupItem.Width = groupItem.ActualWidth * scale;
            }
        }
        private XElement Serialize( DesignerItem item )
        {
            var contentXaml = XElement.Parse( XamlWriter.Save( item.Content ) );

            RewriteImageSource( contentXaml );

            return new XElement( "DesignerItem",
                new XElement( "Left", Canvas.GetLeft( item ) ),
                new XElement( "Top", Canvas.GetTop( item ) ),
                new XElement( "Width", item.Width ),
                new XElement( "Height", item.Height ),
                new XElement( "ID", myIdTransformation.GetId( item.ID ) ),
                new XElement( "zIndex", Canvas.GetZIndex( item ) ),
                new XElement( "IsGroup", item.IsGroup ),
                new XElement( "ParentID", myIdTransformation.GetId( item.ParentID ) ),
                new XElement( "Content",
                    new XAttribute( "Version", "1" ),
                    contentXaml.ToString() )
                );
        }
        private void Group_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            var items = from item in this.SelectionService.CurrentSelection.OfType<DesignerItem>()
                        where item.ParentID == Guid.Empty
                        select item;

            Rect rect = GetBoundingRectangle( items );

            var groupItem = new DesignerItem();
            groupItem.IsGroup = true;
            groupItem.Width = rect.Width;
            groupItem.Height = rect.Height;

            Canvas.SetLeft( groupItem, rect.Left );
            Canvas.SetTop( groupItem, rect.Top );

            var itemContent = new ItemContent();
            // TODO: copy does NOT work
            // itemContent.Properties = new ItemPropertyCollection( items.SelectMany( item => ((ItemContent)item.Content).Properties ) );
            groupItem.Content = itemContent;

            Canvas.SetZIndex( groupItem, Children.Count );

            Children.Add( groupItem );

            foreach( var item in items )
            {
                item.ParentID = groupItem.ID;
            }

            SelectionService.SelectItem( this, groupItem );
        }
        private void DragTop( double scale, DesignerItem item, DesignerCanvas canvas )
        {
            var groupItems = canvas.SelectionService.GetGroupMembers( canvas, item ).Cast<DesignerItem>();

            double groupBottom = Canvas.GetTop( item ) + item.Height;
            foreach ( var groupItem in groupItems )
            {
                double groupItemTop = Canvas.GetTop( groupItem );
                double delta = (groupBottom - groupItemTop) * (scale - 1);
                Canvas.SetTop( groupItem, groupItemTop - delta );
                groupItem.Height = groupItem.ActualHeight * scale;
            }
        }
        private void DragBottom( double scale, DesignerItem item, DesignerCanvas canvas )
        {
            IEnumerable<DesignerItem> groupItems = canvas.SelectionService.GetGroupMembers( canvas, item ).Cast<DesignerItem>();
            double groupTop = Canvas.GetTop( item );
            foreach ( DesignerItem groupItem in groupItems )
            {
                double groupItemTop = Canvas.GetTop( groupItem );
                double delta = (groupItemTop - groupTop) * (scale - 1);

                Canvas.SetTop( groupItem, groupItemTop + delta );
                groupItem.Height = groupItem.ActualHeight * scale;
            }
        }
        private DesignerItem DeserializeDesignerItem( XElement itemXML, Guid id )
        {
            var item = new DesignerItem( id );

            item.Width = Double.Parse( itemXML.Element( "Width" ).Value, CultureInfo.InvariantCulture );
            item.Height = Double.Parse( itemXML.Element( "Height" ).Value, CultureInfo.InvariantCulture );
            item.ParentID = new Guid( itemXML.Element( "ParentID" ).Value );
            item.IsGroup = Boolean.Parse( itemXML.Element( "IsGroup" ).Value );
            Canvas.SetLeft( item, Double.Parse( itemXML.Element( "Left" ).Value, CultureInfo.InvariantCulture ) );
            Canvas.SetTop( item, Double.Parse( itemXML.Element( "Top" ).Value, CultureInfo.InvariantCulture ) );
            Canvas.SetZIndex( item, Int32.Parse( itemXML.Element( "zIndex" ).Value ) );

            DeserializeItemContent( itemXML, item );

            return item;
        }
        private void DeserializeItemContent( XElement itemXML, DesignerItem item )
        {
            var contentContainerElement = itemXML.Element( "Content" );
            var versionAttribute = contentContainerElement.Attribute( "Version" );

            var contentText = ConvertBladeNamespaces(contentContainerElement.Value);

            using (var reader = XmlReader.Create(new StringReader(contentText)))
            {
                var contentXml = XElement.Load(reader);

                RewriteImageSource(contentXml);

                var content = XamlReader.Load(contentXml.CreateReader());

                if (versionAttribute == null)
                {
                    UpgradeItemContent((ItemContent)content);
                }

                item.Content = content;
            }
        }