Daily Demo: Silverlight Mouse 3D Behavior


A very cool new feature in Silverlight 3 is the support of perspective 3D. And now image what you can do with 3D, your Mouse and Behaviors. Apply 3D capabilities to every control you like.

Ta da … the Silverlight Mouse 3D Behavior 

image

Livepreview

 

XAML-Code

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:TheOliver_Controls="clr-namespace:TheOliver.Controls"
    x:Class="Mouse3DBehavior.MainPage"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid
        x:Name="LayoutRoot"
        Background="White">

        <Image
            Source="20080815_114932.jpg"
            Stretch="Fill">
            <i:Interaction.Behaviors>
                <TheOliver_Controls:Mouse3DBehavior />
            </i:Interaction.Behaviors>
        </Image>

    </Grid>
</UserControl>

 

Sourcecode

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;

namespace TheOliver.Controls
{
    public class Mouse3DBehavior : Behavior<UIElement>
    {
        PlaneProjection _planeProjection;
        bool _buttonPressed = false;
        Point _originPoint;
        UIElement _target;
        FrameworkElement _control;
        UIElement _targetParent;
        double _controlHeight;
        double _controlWidth;

        protected override void OnAttached()
        {
            base.OnAttached();

            _target = this.AssociatedObject;
            _control = _target as FrameworkElement;

            _control.LayoutUpdated += (s, e) =>
                {
                    _targetParent = _control.Parent as UIElement;

                    _planeProjection = new PlaneProjection();
                    _target.Projection = _planeProjection;

                    _targetParent.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
                    _targetParent.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
                    _targetParent.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove);
                    _targetParent.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave);

                    _controlHeight = (_targetParent as FrameworkElement).ActualHeight;
                    _controlWidth = (_targetParent as FrameworkElement).ActualWidth;
                };
        }

        void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
        {
            _buttonPressed = false;
        }

        void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _target.CaptureMouse();
            _originPoint = GetPoint(e);
            _buttonPressed = true;
        }

        void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _buttonPressed = false;
            _target.ReleaseMouseCapture();
        }

        void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (_buttonPressed)
            {
                PlaneProjection pp = _target.Projection as PlaneProjection;
                Point pt = GetPoint(e);

                double widthPixPerAngle = _controlWidth / 720;
                double heightPixPerAngle = _controlHeight / 720;

                double diffY = (pt.X - _controlWidth / 2) * widthPixPerAngle;
                double diffX = (pt.Y - _controlHeight / 2) * heightPixPerAngle;

                _originPoint = pt;

                if (YEnable)
                {
                    pp.RotationY = diffY;
                }

                if (XEnable)
                {
                    pp.RotationX = diffX;
                }
            }
        }

        private Point GetPoint(MouseEventArgs e)
        {
            Point point = e.GetPosition(_targetParent);
            return point;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.Projection = null;

            _targetParent.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
            _targetParent.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
            _targetParent.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove);
            _targetParent.MouseLeave -= new MouseEventHandler(AssociatedObject_MouseLeave);
        }

        public double MoveFactor
        {
            get { return (double)GetValue(MoveFactorProperty); }
            set { SetValue(MoveFactorProperty, value); }
        }

        public static readonly DependencyProperty MoveFactorProperty =
            DependencyProperty.Register(
                "MoveFactor",
                typeof(double),
                typeof(Mouse3DBehavior),
                new PropertyMetadata(1.0));

        public bool XEnable
        {
            get { return (bool)GetValue(XEnableProperty); }
            set { SetValue(XEnableProperty, value); }
        }

        public static readonly DependencyProperty XEnableProperty =
            DependencyProperty.Register(
                "XEnable",
                typeof(bool),
                typeof(Mouse3DBehavior),
                new PropertyMetadata(true));

        public bool YEnable
        {
            get { return (bool)GetValue(YEnableProperty); }
            set { SetValue(YEnableProperty, value); }
        }

        public static readonly DependencyProperty YEnableProperty =
            DependencyProperty.Register(
                "YEnable",
                typeof(bool),
                typeof(Mouse3DBehavior),
                new PropertyMetadata(true));
    }
}

 

Solutiondownload

Comments (1)
  1. FrankDeGroot says:

    Cool! Thanks for sharing it. It’s typically something that’s not terribly hard to program but where a sample really saves you time.

    The only oddity is that when I click outside of the center of the image and start dragging the image ‘pops’ into a different perspective before allowing a smooth drag. I need to click in the exact center of the image to prevent that. I’m no expert but I don’t recall that in apps with a similar behavior.

Comments are closed.

Skip to main content