Nomadic is Hiring – Experienced .NET Developer

Date May 26, 2010 @ 11:31 am in Microsoft, Nomadic

As many of you know I recently joined Nomadic, a a full service branding and interactive digital agency in North Scottsdale.  If you haven’t heard of Nomadic, check out our site http://www.nomadicagency.com.  We get to work with some amazing brands and develop some really exciting sites as well as online promotions.

To keep up with the exciting work we have coming in, we are in need of a seasoned .NET developer.  Here is a quick description of the job.

Senior .NET Developer

Key Responsibilities:

  • Serve as the lead programmer on multiple projects.
  • Ability to estimate project tasks, ensuring delivery of projects on-time and to specification
  • Being self-directed and architecturally innovative
  • Help analyze, design, code, test, debug and provide enhancements to existing software.
  • Work closely with a team as well as interfacing with various external Client and Business Groups.

Qualifications

  • Bachelors Degree, MCSD certification or other advanced level of industry certification.
  • Minimum five(5) years working experience with Microsoft .Net (ASP.NET, C# and/or VB.NET).
    • Experience using various separation patterns such as: MVC, MVVM and MVP
  • Minimum two (2) years experience with WCF (Windows Communication Foundation) experience
  • Minimum five(5) years working experience with SQL Server or other advanced level databases
    • Strong database modeling skills
    • Experience  with Object-relational mapping (ORM) using Entity Framework, Linq-To-Sql or  NHibernate.
  • Excellent oral and written professional communication skills that project a positive, professional image.

If you are interested in this opportunity please apply by sending a resume to careers@nomadicagency.com.

Silverlight Connections – November 1-4, 2010

Date May 21, 2010 @ 8:59 am in Microsoft, Silverlight

Dev Connections - Nov 1-4
I am very excited to announce that this year I will be presenting three unique sessions at Silverlight Connections in Las Vegas, Nevada  Nov 1-4, 2010.  I have never got the pleasure of attending this conference and look forward to being a part of three days of in-depth sessions on Silverlight and WP7.

DESIGN
LDS203: Expression Blend Is Not Only for Designers
As a developer if you think that Expression Blend is only for designers, you’re missing out on an incredible opportunity. Interactive developers should embrace Expression blend as a powerful development tool that enhances Visual Studio. Come learn various tips and tricks that will help developers know when to use Blend and when to use Visual Studio. Finding the balance will speed up the development work flow and make you a more powerful developer.

WINDOWS PHONE 7
LWP202: Interaction Design for Windows Phone 7
When building a WP7 application, the nature of the small multi-touch screen requires good interaction design. Our choices around how our users interact with our application will define its success. Learn how to incorporate innovative work flows which build upon the power of the mobile device. In this session, we will look at how the effective use of multi-touch gestures, panoramic layouts and the effective use of transitions can take your app to the next level.

ANIMATIONS
LAN201: Using Silverlight Animations to Improve User Experience in LOB Applications
In this session, we will look at the use of animations and natural movement to enhance a user’s interaction with Silverlight LOB applications. Find out how simple effects, natural easing and fluid transitions can improve how your users navigate throughout your application.

Windows Phone 7 Developer Tools April 2010 Refresh

Date April 29, 2010 @ 10:36 am in Microsoft, Silverlight, Windows Phone 7

Today Microsoft released the latest version of the Windows Phone 7 Developer tools.   This version is free to the community and will will work correctly with Visual Studio 2010 final release. Click here to download the tools.

Silverlight 4 How to Command Control

Date February 6, 2010 @ 11:20 am in Silverlight

SilverlightCheckout my latest article on the use of commanding in Silverlight 4. In this article I demonstrate how through the use of commanding and intelligent binding we can virtually eliminate all code behind and implement to a strong MVVM architectural pattern.

Silverlight 4 Webcam Article

Date December 12, 2009 @ 12:08 pm in Silverlight

SilverlightCheckout my latest article on the use of  the Webcam in Silverlight 4. The article demonstrates how to attach to a device apply a PixelShader then store a captured JPEG in Isolated Storage .

Navigation Transitions with WriteableBitmap

Date August 14, 2009 @ 10:16 am in Silverlight

If you have not had a chance to play with Navigation Frames in Silverlight they are very cool, they give developers the ability to navigate between "Page" within a single Silverlight Solution.  The first time I used them I could believe how easy it was to implement.  You simply add a few pages to your solution, drop a Navigation:Frame on to your MainPage.xaml UserControl and define some UriMappers.

One thing that i thought was missing was the ability to  create nice looking transitions between pages as they are loaded into a frame.  Recently I voiced my complaint to a coworker (the infamous Steve Saxon – @xmlguy) and he had the great idea of using a WritableBitmap to capture the current and next page within the Frame, than animating the images.  Here is the solution I arrived at.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
 
namespace NavigationTransition
{
    public partial class MainPage : UserControl
    {
        private HyperlinkButton _lastClicked;
        private bool _isNavigating = false;
        private readonly Image _imgLast = new Image();
        private readonly Image _imgNext = new Image();
        private Storyboard _sb = new Storyboard();
 
        public MainPage()
        {
            InitializeComponent();
        }
 
        void SbCompleted(object sender, EventArgs e)
        {
            Panel panel = ContentFrame.Parent as Panel;
            panel.Children.Remove(_imgLast);
            panel.Children.Remove(_imgNext);
            ContentFrame.Visibility = Visibility.Visible;
            _sb.Stop();
            _isNavigating = false;
        }
 
        private void ContentFrameNavigated(object sender, NavigationEventArgs e)
        {
            ContentFrame.Navigated -= ContentFrameNavigated;
            Panel panel = ContentFrame.Parent as Panel;
            panel.UpdateLayout();
 
            WriteableBitmap bitmapN = new WriteableBitmap(ContentFrame, new TranslateTransform());
            _imgNext.Source = bitmapN;
            TranslateTransform ttNext = new TranslateTransform();
 
            _imgNext.RenderTransform = ttNext;
            panel.Children.Add(_imgNext);
 
            _sb.Children.Add(CreateDoubleAnimation(ttNext, "X", -bitmapN.PixelWidth, 0, true)); 
            ContentFrame.Visibility = Visibility.Collapsed;
 
            _sb.Begin();
 
        }
 
 
        private void Nav_Click(object sender, RoutedEventArgs e)
        {
            _lastClicked = (HyperlinkButton)sender;
            if (ContentFrame.Source.ToString() != _lastClicked.Tag.ToString() && !_isNavigating)
            {
                _sb = new Storyboard();
                _sb.Completed += SbCompleted;
 
                Panel panel = ContentFrame.Parent as Panel;
 
                WriteableBitmap bitmapL = new WriteableBitmap(ContentFrame, new TranslateTransform());
                _imgLast.Source = bitmapL;
                TranslateTransform ttLast = new TranslateTransform();
                _imgLast.RenderTransform = ttLast;
                if (panel != null) panel.Children.Add(_imgLast);
 
                ContentFrame.Navigated += ContentFrameNavigated;
                ContentFrame.Navigate(new Uri(_lastClicked.Tag.ToString(), UriKind.Relative));
 
                _sb.Children.Add(CreateDoubleAnimation(ttLast, "X", 0, bitmapL.PixelWidth, true));
 
                _isNavigating = true;
            }  
        }
        private static DoubleAnimation CreateDoubleAnimation(DependencyObject element, 
              string property, double from, double to, bool addEasing)
        {
            DoubleAnimation da = new DoubleAnimation();
            da.To = to;
            da.From = from;
            if (addEasing)
                da.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 };
 
 
            Storyboard.SetTargetProperty(da, new PropertyPath(property));
            Storyboard.SetTarget(da, element);
            return da;
        }
        // If an error occurs during navigation, show an error window
        private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            e.Handled = true;
            ChildWindow errorWin = new ErrorWindow(e.Uri);
            errorWin.Show();
        }
    }
}

One of the things I found necessary was to delay the navigation so that I could capture a bitmap of the current frame.  The way I intersected the navigation  was to attach a Click event handler to my HyperlinkButton and then store the Uri in the Tag property.  With a little more effort you could make this into a Behavior or even add a few additional types of transitions.

 


Code: NavigationTransition.zip

Control Visibility with triggers

Date August 10, 2009 @ 2:30 pm in Silverlight

I absolutely love writing triggers for Silverlight 3.  As UX developers we often faced with the challenge of finding ways to fit a ton of information on a single user input screen.  On occasion, some of that information may only be relevant to display if users have made certain choices on the interface: checking a box, selecting an item in a combobox or listbox.  In this post I will include two custom TargetedTriggerAction’s which allow a developer to easily tie a UIElement’s visibility to an action made on another control.

VisibilityIsChecked

This first trigger I very simple.  I wanted the ability to tie a checkbox to the visibility of another UIElement.  Since a checkbox derives from ToggleButton we can get creative and write a single trigger that will work with either a CheckBox, RadioButton or ToggleButton.  Here is how I did it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Interactivity;
 
namespace VisibilityTriggers
{
    public class VisibilityIsChecked : TargetedTriggerAction<frameworkelement>
    {
        public static readonly DependencyProperty VisibleWhenCheckedProperty =
            DependencyProperty.Register(&quot;VisibleWhenChecked&quot;, typeof(bool), 
            typeof(VisibilityIsChecked), new PropertyMetadata(true));
        public bool VisibleWhenChecked
        {
            get
            {
                return (bool)GetValue(VisibleWhenCheckedProperty);
            }
            set
            {
                SetValue(VisibleWhenCheckedProperty, value);
            }
        }
 
        protected override void OnAttached()
        {
            base.OnAttached();
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            if (element != null) element.Loaded += TargetLoaded;
        }
 
        void TargetLoaded(object sender, RoutedEventArgs e)
        {
            ToggleButton tb = this.AssociatedObject as ToggleButton;
            SetVisibility(tb);
        }
        protected override void Invoke(object parameter)
        {
            RoutedEventArgs args = parameter as RoutedEventArgs;
 
            if (args != null)
            {
                ToggleButton tb = args.OriginalSource as ToggleButton;
                SetVisibility(tb);
            }
        }
 
        private void SetVisibility(ToggleButton tb)
        {
            if (tb != null)
            {
                Target.Visibility = ((bool)tb.IsChecked == VisibleWhenChecked) ? 
                Visibility.Visible : Visibility.Collapsed;
            }
        }
    }
}

To implement this trigger, we simply add an EventTrigger to a checkbox and set the TargetName to the control I want to visualize. Since there are times that we want IsChecked to either show or hide the element I have included a DependencyProperty called VisibileWhenChecked that can alter this behavior.

1
2
3
4
5
6
7
8
<checkbox content="Show?" margin="5">
    <i:interaction.triggers>
        <i:eventtrigger eventname="Click">
            <triggers:visibilityischecked targetname="rectangle" />
        </i:eventtrigger>
    </i:interaction.triggers>
</checkbox>
<rectangle margin="10" x:name="rectangle" width="100" height="100" fill="Yellow" visibility="Collapsed" />

VisibilitySelectedItem

The second TargetedTriggerAction I created achieves a similar result, but instead of targeting a checkbox or radio button, it targets a ComboBox or ListBox. In this trigger I will flip a UIElements visibility based on a specific value being returned from a selection in the the ListBox. Here is how I implemented the trigger.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Interactivity;
 
namespace VisibilityTriggers
{
    public class VisibilitySelectedItem : TargetedTriggerAction<frameworkelement>
    {
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register(&quot;Value&quot;, typeof(object), typeof(VisibilitySelectedItem), null);
 
        public object Value
        {
            get
            {
                return (object)GetValue(ValueProperty);
            }
            set
            {
                SetValue(ValueProperty, value);
            }
        }
 
        public static readonly DependencyProperty MatchMemberPathProperty =
            DependencyProperty.Register(&quot;MatchMemberPath&quot;, typeof(string), typeof(VisibilitySelectedItem), new PropertyMetadata(&quot;Content&quot;));
 
        public string MatchMemberPath
        {
            get
            {
                return (string)GetValue(MatchMemberPathProperty);
            }
            set
            {
                SetValue(MatchMemberPathProperty, value);
            }
        }
 
        protected override void OnAttached()
        {
            base.OnAttached();
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            if (element != null) element.Loaded += TargetLoaded;
        }
 
        void TargetLoaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            Selector cb = this.Target as Selector;
            if (cb != null)
            {
                int index = cb.SelectedIndex &gt; -1 ? cb.SelectedIndex : 0;
                object item = (cb.Items.Count &gt; 0) ? cb.Items[index] as object : null;
 
                if (item != null)
                {
                    System.Reflection.PropertyInfo pi = item.GetType().GetProperty(MatchMemberPath);
                    var value = (pi != null) ? pi.GetValue(item, null) as object : item;
                    bool match = Equals(value, Value);
                    if (element != null) element.Visibility = match ? Visibility.Visible : Visibility.Collapsed;
                }
            }
        }
        protected override void Invoke(object parameter)
        {
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            SelectionChangedEventArgs args = parameter as SelectionChangedEventArgs;
 
            if (args != null)
            {
                IList list = args.AddedItems as IList;
                if (list != null)
                {
                    foreach (object item in list)
                    {
                        System.Reflection.PropertyInfo pi = item.GetType().GetProperty(MatchMemberPath);
                        var value = (pi != null) ? pi.GetValue(item, null) as object : item;
 
                        bool match = Equals(value, Value);
                        if (element != null) element.Visibility = match ? Visibility.Visible : Visibility.Collapsed;
                    }
                }
            }
        }
    }
}

To implement this TargetedTriggerAction you will place the custom EventTrigger on the item you want to visualize and target the SelectionChanged event on the ListBox (or ComboBox). Since we only want to visualize when a specific value is returned, we will also specifiy a "Value" and which property of our ListBox’s ItemSource we are targeting (MatchMemeberPath). The following is one way in which we can implement the trigger. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<listbox x:name="myComboBox2" width="100" itemssource="{Binding Path=Items}" displaymemberpath="Description" />
<rectangle margin="10" width="100" height="100" fill="Silver" visibility="Collapsed">
    <i:interaction.triggers>
        <i:eventtrigger eventname="SelectionChanged" sourcename="myComboBox2">
            <triggers:visibilityselecteditem targetname="myComboBox2" value="I1" matchmemberpath="Code" />
        </i:eventtrigger>
    </i:interaction.triggers>
</rectangle>
<ellipse margin="10" width="100" height="100" fill="SaddleBrown" visibility="Collapsed">
    <i:interaction.triggers>
        <i:eventtrigger eventname="SelectionChanged" sourcename="myComboBox2">
            <triggers:visibilityselecteditem targetname="myComboBox2" value="I2" matchmemberpath="Code" />
        </i:eventtrigger>
    </i:interaction.triggers>
</ellipse>





Code: VisibilityTriggers.zip

Silverlight 3 Flip TargetedTriggerAction

Date August 6, 2009 @ 3:36 pm in Silverlight

Last week I created a Trigger Action which flipped a panel. It was intended to be invoked from clicking on the panel directly. Earlier today I was asked if you could invoke this trigger from multiple places. The answer is no, but it is very easily to rewrite this trigger to achieve this behavior. In this blog post I am going to create a TargetedTriggerAction which allows me to add the trigger to a button or multiple UIElement and “Target” a panel to be flipped. What is really cool about this approach is that each button can contain the logic used to flip the panel (Storyboard direction, duration, etc).

The following is the code I used to create my Flip TargetedTriggerAction.

using System.ComponentModel;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
 
namespace FlipTargetedTrigger
{
    public enum RotationDirection
    {
        LeftToRight,
        RightToLeft,
        TopToBottom,
        BottomToTop
    }
 
    public class Flip : TargetedTriggerAction<FrameworkElement>
    {
        public static readonly DependencyProperty FrontElementNameProperty =
            DependencyProperty.Register("FrontElementName", typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
 
        [Category("Flip Properties")]
        public string FrontElementName
        {
            get
            {
                return (string)GetValue(FrontElementNameProperty);
            }
            set
            {
                SetValue(FrontElementNameProperty, value);
            }
        }
 
        public static readonly DependencyProperty BackElementNameProperty =
            DependencyProperty.Register("BackElementName", typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
 
        [Category("Flip Properties")]
        public string BackElementName
        {
            get
            {
                return (string)GetValue(BackElementNameProperty);
            }
            set
            {
                SetValue(BackElementNameProperty, value);
            }
        }
 
        public static readonly DependencyProperty DurationProperty =
            DependencyProperty.Register("Duration", typeof(Duration),
                                        typeof(Flip), new PropertyMetadata(null));
 
        [Category("Animation Properties")]
        public Duration Duration
        {
            get
            {
                return (Duration)GetValue(DurationProperty);
            }
            set
            {
                SetValue(DurationProperty, value);
            }
        }
 
        public static readonly DependencyProperty RotationProperty =
            DependencyProperty.Register("Rotation", typeof(RotationDirection),
                                        typeof(Flip), new PropertyMetadata(RotationDirection.LeftToRight));
 
        [Category("Animation Properties")]
        public RotationDirection Rotation
        {
            get
            {
                return (RotationDirection)GetValue(RotationProperty);
            }
            set
            {
                SetValue(RotationProperty, value);
            }
        }
 
        public static readonly DependencyProperty FrontStoryboardProperty =
            DependencyProperty.Register("FrontStoryboard", typeof(Storyboard), typeof(Flip), null);
 
        public Storyboard FrontStoryBoard
        {
            get
            {
                return (Storyboard)GetValue(FrontStoryboardProperty);
            }
        }
        public static readonly DependencyProperty BackStoryboardProperty =
            DependencyProperty.Register("BackStoryboard", typeof(Storyboard), typeof(Flip), null);
 
        public Storyboard BackStoryboard
        {
            get
            {
                return (Storyboard)GetValue(BackStoryboardProperty);
            }
        }
 
        private bool _forward = true;
 
        protected override void OnAttached()
        {
            base.OnAttached();
            FrameworkElement element = this.AssociatedObject as FrameworkElement;
            if (element != null) element.Loaded += TargetLoaded;
        }
 
        void TargetLoaded(object sender, RoutedEventArgs e)
        {
            PlaneProjection pp = Target.Projection as PlaneProjection;
            if (Target.Projection == null)
            {
                pp = new PlaneProjection { CenterOfRotationY = .51 };
 
                Target.RenderTransformOrigin = new Point(.5, .5);
                Target.Projection = pp;
            }
 
            Storyboard sbF = new Storyboard();
            Storyboard sbB = new Storyboard();
 
            UIElement f = null;
            UIElement b = null;
 
            f = Target.FindName(FrontElementName) as UIElement;
            if (f != null)
            {
                PlaneProjection ppFront = new PlaneProjection { CenterOfRotationY = .51 };
                f.Projection = ppFront;
                f.RenderTransformOrigin = new Point(.5, .5);
            }
            b = Target.FindName(BackElementName) as UIElement;
            if (b != null)
            {
                PlaneProjection ppBack = new PlaneProjection { CenterOfRotationY = .51, RotationY = 180.0 };
                b.Projection = ppBack;
                b.RenderTransformOrigin = new Point(.5, .5);
                b.Opacity = 0.0;
            }
 
 
            double to = 0.0;
            double from = 180.0;
            string property = "RotationY";
 
            switch (Rotation)
            {
                case RotationDirection.RightToLeft:
                    to = 180.0;
                    from = 0.0;
                    break;
                case RotationDirection.TopToBottom:
                    property = "RotationX";
                    break;
                case RotationDirection.BottomToTop:
                    to = 0.0;
                    from = 180.0;
                    property = "RotationX";
                    break;
            }
 
            sbF.Duration = Duration;
            sbB.Duration = Duration;
 
            sbF.Children.Add(CreateDoubleAnimation(pp, property, from, to, true));
            sbB.Children.Add(CreateDoubleAnimation(pp, property, to, from, true));
 
            sbF.Children.Add(CreateDoubleAnimation(f, "Opacity", 1.0, 0.0, false));
            sbB.Children.Add(CreateDoubleAnimation(f, "Opacity", 0.0, 1.0, false));
 
            sbF.Children.Add(CreateDoubleAnimation(b, "Opacity", 0.0, 1.0, false));
            sbB.Children.Add(CreateDoubleAnimation(b, "Opacity", 1.0, 0.0, false));
 
            SetValue(FrontStoryboardProperty, sbF);
            SetValue(BackStoryboardProperty, sbB);
 
 
        }
 
        protected override void Invoke(object parameter)
        {
            Storyboard sbF = GetValue(FrontStoryboardProperty) as Storyboard;
            Storyboard sbB = GetValue(BackStoryboardProperty) as Storyboard;
 
            if (_forward)
            {
                sbF.Begin();
                _forward = false;
            }
            else
            {
                sbB.Begin();
                _forward = true;
            }
        }
 
        private static DoubleAnimation CreateDoubleAnimation(DependencyObject element, string property, double from,
                                                             double to, bool addEasing)
        {
            DoubleAnimation da = new DoubleAnimation();
            da.To = to;
            da.From = from;
            if (addEasing)
                da.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 };
 
            Storyboard.SetTargetProperty(da, new PropertyPath(property));
            Storyboard.SetTarget(da, element);
            return da;
        }
    }
}

For the most part the code is very simmiler to the other trigger. When you inherate from TargetTriggerAction you gain access to a new property called “Target” this will contain a reference to the UIELement I plan on flipping. Instead of adding my PlainProjection to the AssociatedObject I instead add it to the target. I made a few other changes like storing my Storyboards as dependency properties which allow me to reuse the same animiation each time I lick the button. These DependencyProperites get stored in the AssociatedObject and not the Target. This allows each item being clicked to have a unique animation. Below is how I implement the TargetTriggerAction.

<StackPanel Orientation="Vertical">
    <Grid Margin="10" x:Name="flipMe">
        <StackPanel x:Name="back1" Height="200" Width="200" HorizontalAlignment="Center" 
                    VerticalAlignment="Center">
            <Rectangle Fill="Green" Height="200" Width="200" StrokeThickness="1" Stroke="Black" />
        </StackPanel>
        <Rectangle x:Name="front1" Fill="Gold" Height="200" Width="200" 
                   HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
    <Button Content="Flip RightToLeft" Width="100">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <targeted:Flip FrontElementName="front1" BackElementName="back1" 
                               TargetName="flipMe" Duration="00:00:1" Rotation="RightToLeft"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
    <Button Content="Flip TopToBtoom" Width="100">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <targeted:Flip FrontElementName="front1" BackElementName="back1" 
                               TargetName="flipMe" Duration="00:00:1" Rotation="TopToBottom"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
</StackPanel>




Code: FlipTargetedTrigger.zip

Silverlight 3 Flip TriggerAction

Date July 30, 2009 @ 11:26 am in Microsoft, Silverlight

flip1In this blog post I am going to create a TriggerAction which makes it incredibly simple to take two UIElements and compose them into a panel which can be flipped. I have demonstrated the technique many times, but here it is all packaged up in a nice reusable class.

The following is the code I used to create by Flip TriggerAction.

using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Interactivity;
using System.ComponentModel;
 
namespace FlipTriggerAction
{
    public enum RotationDirection
    {
        LeftToRight,
        RightToLeft,
        TopToBottom,
        BottomToTop
    }
 
    public class Flip : TriggerAction<FrameworkElement>
    {
        public static readonly DependencyProperty FrontElementNameProperty =
            DependencyProperty.Register("FrontElementName", typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
 
        [Category("Flip Properties")]
        public string FrontElementName { get; set; }
 
        public static readonly DependencyProperty BackElementNameProperty =
            DependencyProperty.Register("BackElementName", typeof(string),
                                        typeof(Flip), new PropertyMetadata(null));
 
        [Category("Flip Properties")]
        public string BackElementName { get; set; }
 
        public static readonly DependencyProperty DurationProperty =
            DependencyProperty.Register("Duration", typeof(Duration),
                                        typeof(Flip), new PropertyMetadata(null));
 
        [Category("Animation Properties")]
        public Duration Duration { get; set; }
 
        public static readonly DependencyProperty RotationProperty =
            DependencyProperty.Register("Rotation", typeof(RotationDirection),
                                        typeof(Flip), new PropertyMetadata(RotationDirection.LeftToRight));
 
        [Category("Animation Properties")]
        public RotationDirection Rotation { get; set; }
 
        private readonly Storyboard _sbF = new Storyboard();
        private readonly Storyboard _sbB = new Storyboard();
        private bool _forward = true;
 
        protected override void Invoke(object parameter)
        {
            if (AssociatedObject.Projection == null)
            {
                FrameworkElement parent = AssociatedObject as FrameworkElement;
                UIElement f = null;
                UIElement b = null;
 
                if (parent != null)
                {
                    f = parent.FindName(FrontElementName) as UIElement;
                    if (f != null)
                    {
                        PlaneProjection ppFront = new PlaneProjection { CenterOfRotationY = .51 };
                        f.Projection = ppFront;
                        f.RenderTransformOrigin = new Point(.5, .5);
                    }
                    b = parent.FindName(BackElementName) as UIElement;
                    if (b != null)
                    {
                        PlaneProjection ppBack = new PlaneProjection { CenterOfRotationY = .51, RotationY = 180.0 };
                        b.Projection = ppBack;
                        b.RenderTransformOrigin = new Point(.5, .5);
                        b.Opacity = 0.0;
                    }
                }
 
                PlaneProjection pp = new PlaneProjection { CenterOfRotationY = .51 };
 
                AssociatedObject.RenderTransformOrigin = new Point(.5, .5);
                AssociatedObject.Projection = pp;
 
                double to = 180.0;
                double from = 0.0;
                string property = "RotationY";
 
                switch (Rotation)
                {
                    case RotationDirection.RightToLeft:
                        to = 0.0;
                        from = 180.0;
                        break;
                    case RotationDirection.TopToBottom:
                        property = "RotationX";
                        break;
                    case RotationDirection.BottomToTop:
                        to = 0.0;
                        from = 180.0;
                        property = "RotationX";
                        break;
                }
 
                _sbF.Duration = Duration;
                _sbB.Duration = Duration;
 
                _sbF.Children.Add(CreateDoubleAnimation(pp, property, from, to, true));
                _sbB.Children.Add(CreateDoubleAnimation(pp, property, to, from, true));
 
                _sbF.Children.Add(CreateDoubleAnimation(f, "Opacity", 1.0, 0.0, false));
                _sbB.Children.Add(CreateDoubleAnimation(f, "Opacity", 0.0, 1.0, false));
 
                _sbF.Children.Add(CreateDoubleAnimation(b, "Opacity", 0.0, 1.0, false));
                _sbB.Children.Add(CreateDoubleAnimation(b, "Opacity", 1.0, 0.0, false));
            }
            if (_forward)
            {
                _sbF.Begin();
                _forward = false;
            }
            else
            {
                _sbB.Begin();
                _forward = true;
            }
        }
 
        private static DoubleAnimation CreateDoubleAnimation(DependencyObject element, string property, double from,
                                                             double to, bool addEasing)
        {
            DoubleAnimation da = new DoubleAnimation();
            da.To = to;
            da.From = from;
            if (addEasing)
                da.EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 };
 
 
            Storyboard.SetTargetProperty(da, new PropertyPath(property));
            Storyboard.SetTarget(da, element);
            return da;
        }
    }
}

Once you have the class constructed you can add the trigger to your UIElement in Blend. Clicking on the trigger in the Object & Timeline tab will allow you to configure each of the the properties you have defined in your class.
flip2


Code: FlipTriggerAction.zip

Silverlight 3 Drag Behavior

Date July 30, 2009 @ 10:35 am in Microsoft, Silverlight

By now most Silverlight developers should have stumbled on a great new feature of Silverlight 3 and Expression Blends, custom Triggers and Behaviors. I seriously don’t know how I lived without them!

drag_1In this blog post I am going to demonstrate a simple, yet useful, example of a behavior which allows a UIElement to become drag able. Figure 1 show the view of my XAML from within Blend. For this example I will create an image with a rounded border which has been placed within a Grid. In the center of my grid I have a Red Rectangle.

To create my Behavior I will jump in to VS2008 and create a new class that will reside within my solution. If my goal was to create a collection of generic behaviors and triggers I would likely create a Silverlight class assembly and deploy it to the library folder within Blend. This would allow my custom behaviors to be available to all Silverlight or WPF project. The following demonstrates the code I used to create by Drag behavior.

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Interactivity;
using System.Windows.Media.Imaging;
 
namespace DragBehaviors
{
    public class Drag : Behavior
    {
        public static readonly DependencyProperty IsMovableProperty =
            DependencyProperty.Register("IsMovable", typeof(bool),
                                        typeof(Drag), new PropertyMetadata(null));
 
        [Category("Target Properties")]
        public bool IsMovable { get; set; }
 
        private bool _isDragging = false;
        private Point _offset;
        private readonly TranslateTransform _elementTranslate = new TranslateTransform();
        private TranslateTransform _imgTranslate = new TranslateTransform();
        private Image _img = new Image();
 
        protected override void OnAttached()
        {
            base.OnAttached();
 
            AssociatedObject.Loaded += AssociatedObjectLoaded;
            AssociatedObject.HorizontalAlignment = HorizontalAlignment.Left;
            AssociatedObject.VerticalAlignment = VerticalAlignment.Top;
            AssociatedObject.MouseLeftButtonDown += AssociatedObjectMouseLeftButtonDown;
        }
 
        void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
        {
            AssociatedObject.RenderTransform = _elementTranslate;
        }
 
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.MouseLeftButtonDown -= AssociatedObjectMouseLeftButtonDown;
        }
 
        private void AssociatedObjectMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (!_isDragging) return;
            FrameworkElement parent = _img.Parent as FrameworkElement;
            Point newPosition = e.GetPosition(parent);
 
            // Move the dragon via the new position less the offset
            _imgTranslate.X = (newPosition.X - _offset.X);
            _imgTranslate.Y = (newPosition.Y - _offset.Y);
        }
 
        private void AssociatedObjectMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (!_isDragging) return;
            Panel panel = AssociatedObject.Parent as Panel;
 
            // turn off drag
            _isDragging = false;
 
            // Free the Mouse
            _img.ReleaseMouseCapture();
            _img.MouseMove -= AssociatedObjectMouseMove;
            _img.MouseLeftButtonUp -= AssociatedObjectMouseLeftButtonUp;
 
            if (IsMovable)
            {
                _elementTranslate.X = _imgTranslate.X;
                _elementTranslate.Y = _imgTranslate.Y;
            }
            _imgTranslate = new TranslateTransform();
            _offset = new Point(0, 0);
            AssociatedObject.Opacity = 1;
            if (panel != null) panel.Children.Remove(_img);
            _img = new Image();
        }
 
        private void AssociatedObjectMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _isDragging = true;
 
            AssociatedObject.Opacity = .35;
 
            WriteableBitmap bitmap = new WriteableBitmap(AssociatedObject, new TranslateTransform());
            if (_img == null) return;
 
            _img.Source = bitmap;
            _img.HorizontalAlignment = HorizontalAlignment.Left;
            _img.VerticalAlignment = VerticalAlignment.Top;
            _img.Stretch = Stretch.None;
            _img.Width = bitmap.PixelWidth;
            _img.Height = bitmap.PixelHeight;
 
            _imgTranslate.X = _elementTranslate.X;
            _imgTranslate.Y = _elementTranslate.Y;
 
            _img.RenderTransform = _imgTranslate;
            _img.MouseMove += AssociatedObjectMouseMove;
            _img.MouseLeftButtonUp += AssociatedObjectMouseLeftButtonUp;
 
            Panel panel = AssociatedObject.Parent as Panel;
 
            if (panel != null) panel.Children.Add(_img);
 
            _offset = e.GetPosition(_img);
            _img.CaptureMouse();
        }
    }
}

For the most part the code should be self explanatory. One cool thing I did was that when I first begin dragging the UIElement, I convert it to a Bitmap and drag an image. The idea is that it will be more efficient to move a image around the screen then the actual collection of UIElements. Once I drop the image than I physically move the UIElement. Note that in its current state this only works correctly if the UIElement I am dragging is Left and Top aligned. This ensures that it is sitting at X=0, Y=0 in the panel it is residing. My guess is that it could be rewritten to support other alignments.

Once the Behavior class is constructed we simply add it to the control we want to drag.

<Border BorderThickness="1" BorderBrush="Black" CornerRadius="6" 
    HorizontalAlignment="Center" VerticalAlignment="Center">
    <i:Interaction.Behaviors>
        <behaviors:Drag IsMovable="True"/>
    </i:Interaction.Behaviors>
    <Grid>
        <Image Source="4.jpg" Width="100" Height="100" Stretch="UniformToFill"/>
        <TextBlock Text="Image" FontWeight="Bold" FontSize="20" 
            Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Border>


Code: DragBehavior.zip