Sharker Khaleed Mahmud Silverlight Tips & Tricks

September 4, 2010

87. Adding DropTargetValidation to MouseDragElementBehavior in Silverlight

Filed under: Silverlight — Tags: — Sharker Khaleed Mahmud | shamrat231 @ 6:44 AM

[tweetmeme source=”shamrat231” only_single=false]

One of the testers gave me a scenario where the objects get lost to a project I worked some time ago.  This happened due to the use of MouseDragElementBehavior. To explain more of the scenario, open the live link given below. 

You can see the live example here [live demo]   

The SOURCE CODE(.zip) is at the end of the page for download.

For demonstration purpose, I will be using an one piece anime image from deviant art gallery. Starting from the left side, drag the first object out from the box and then release your mouse. You would notice that the object can not be seen anymore. This happens to be the case when you donot restrict an object in a particular bound.

MainPage.xaml
            <Canvas x:Name=”MainHostDemo1″ Background=”#b0b0b3″ Width=”250″ Height=”384″ Margin=”20″>
                <Canvas.Clip>
                    <RectangleGeometry Rect=”0,0,250,384″ />
                </Canvas.Clip>
                <Image Source=”Images/one-piece.jpg”>
                    <i:Interaction.Behaviors>
                        <ei:MouseDragElementBehavior />
                    </i:Interaction.Behaviors>
                </Image>
            </Canvas>

Now a possible solution to the problem would be to use <ei:MouseDragElementBehavior ConstrainToParentBounds=”True” />. If that is the case, then try dragging the second object from the box. Notice that for object that are bigger than the restricted zone…do not works out well.

MainPage.xaml
            <Canvas x:Name=”MainHostDemo2″ Background=”#b0b0b3″ Width=”250″ Height=”384″ Margin=”20″>
                <Canvas.Clip>
                    <RectangleGeometry Rect=”0,0,250,384″ />
                </Canvas.Clip>
                <Image Source=”Images/one-piece.jpg”>
                    <i:Interaction.Behaviors>
                        <ei:MouseDragElementBehavior ConstrainToParentBounds=”True” />
                    </i:Interaction.Behaviors>
                </Image>
            </Canvas>

So basically, I will be customizing the MouseDragElementBehavior to support this kind of scenario where the objects do not get lost.

So let’s start by creating a custom class inheriting our default dragelementbehaviour.

Now to make an object reset to its original position, I will add this new property

1. ResetX : This will deal with the X position that the object should get reset to. It could be the objects initial postion or at any position the user chooses to.

2. ResetY : This will deal with the Y position that the object should get reset to. It could be the objects initial postion or at any position the user chooses to.

3. AllowDropWidth : This property validate the amount of X plane that the object can move around without getting reset.

4. AllowDropHeight: This property validates the amount of Y plane that the object can move around without getting reset.

5. IsDropTargetValidate: This is a Boolean variable that determines if the object drop position needs to be validated.

Now let’s add this property in our CustomDragBehaviour

        #region ResetX
        public static readonly DependencyProperty ResetXProperty = DependencyProperty
            .Register(“ResetX”, typeof(double), typeof(CustomDragBehaviour), null);

        public double ResetX
        {
            get { return (double)this.GetValue(CustomDragBehaviour.ResetXProperty); }
            set { this.SetValue(CustomDragBehaviour.ResetXProperty, value); }
        }
        #endregion

        #region ResetY
        public static readonly DependencyProperty ResetYProperty = DependencyProperty
            .Register(“ResetY”, typeof(double), typeof(CustomDragBehaviour), null);

        public double ResetY
        {
            get { return (double)this.GetValue(CustomDragBehaviour.ResetYProperty); }
            set { this.SetValue(CustomDragBehaviour.ResetYProperty, value); }
        }
        #endregion

        #region AllowDropWidth
        public static readonly DependencyProperty AllowDropWidthProperty = DependencyProperty
            .Register(“AllowDropWidth”, typeof(double), typeof(CustomDragBehaviour), null);

        public double AllowDropWidth
        {
            get { return (double)this.GetValue(CustomDragBehaviour.AllowDropWidthProperty); }
            set { this.SetValue(CustomDragBehaviour.AllowDropWidthProperty, value); }
        }
        #endregion

        #region AllowDropHeight
        public static readonly DependencyProperty AllowDropHeightProperty = DependencyProperty
            .Register(“AllowDropHeight”, typeof(double), typeof(CustomDragBehaviour), null);

        public double AllowDropHeight
        {
            get { return (double)this.GetValue(CustomDragBehaviour.AllowDropHeightProperty); }
            set { this.SetValue(CustomDragBehaviour.AllowDropHeightProperty, value); }
        }
        #endregion

        #region IsDropTargetValidate
        public static readonly DependencyProperty IsDropTargetValidateProperty = DependencyProperty
            .Register(“IsDropTargetValidate”, typeof(bool), typeof(CustomDragBehaviour),null);

        public bool IsDropTargetValidate
        {
            get { return (bool)this.GetValue(CustomDragBehaviour.IsDropTargetValidateProperty); }
            set { this.SetValue(CustomDragBehaviour.IsDropTargetValidateProperty, value); }
        }
        #endregion

Look at the above picture. I am using my new CustomDragBehaviour. I am setting IsDropTargetValidate=”true”. When the object gets out of the region, it can reset to any position that you assigned . Now allowing the amount of XY plane that the object can move around freely should be equal to the amount to the view region. So instead of giving hardcoded value, I am binding it to the parent width and height.

Now comes the part where we implement the moment validation rule. In this example, the validation needs to happen when the user releases the mouse. In behavior, we usually do that on two properties as shown in the code

        protected override void OnAttached()
        {
            base.OnAttached();
            if (IsDropTargetValidate)
                this.AssociatedObject.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            if (IsDropTargetValidate)
                this.AssociatedObject.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
        }

In here, I am adding an MouseLeftButtonUp handler when the object gets attached…and removing it when the objects get detached. Inside the event now apply the validation as written below. 

        void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var img = (Image)sender;

            if (this.X >= ResetX + AllowDropWidth || this.Y >= ResetY + AllowDropHeight || this.X <= -(img.ActualWidth – ResetX) || this.Y <= -(img.ActualHeight – ResetY))
            {
                this.X = ResetX;
                this.Y = ResetY;
            }
        }

For easy of setting the reset value, you could uncomment the Message written below. Change reset value to make left/right equal.

        void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var img = (Image)sender;

            //resetX and resetY value is respective to MainCanvas

            //<il:CustomDragBehaviour ResetX=”600″ ResetY=”20″ />
            //so +/- resetX[value] at XAML till the image moves exactly at the right boundary line. When that happens both left/right[value] will become equal.
            //MessageBox.Show(X + “==” + (ResetX + AllowDropWidth)); //right validation

            //so +/- resetY[value] at XAML till the image moves exactly at the bottom boundary line. When that happens both left/right[value] will become equal.
            //MessageBox.Show(Y + “==” + (ResetY + AllowDropHeight)); // bottom validation

            //no need to change here….
            if (this.X >= ResetX + AllowDropWidth || this.Y >= ResetY + AllowDropHeight || this.X <= -(img.ActualWidth – ResetX) || this.Y <= -(img.ActualHeight – ResetY))
            {
                this.X = ResetX;
                this.Y = ResetY;
            }
        }

As always, you can download the source code from here [download link]

Sharker Khaleed Mahmud
Web Developer

Advertisements

1 Comment »

  1. […] Adding DropTargetValidation to MouseDragElementBehavior in Silverlight (Sharker Khaleed Mahmud) […]

    Pingback by Windows Client Developer Roundup 040 for 9/6/2010 - Pete Brown's 10rem.net — September 6, 2010 @ 7:49 AM


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: