views:

25

answers:

2

I've implemented a drag and drop that is mostly working in my Silverlight 4 app. Once the users have dropped the shapes onto the canvas, I wanted to use Size & Child Decorators. I've tried to implement the sample code. Code below is problem section of much larger app.

xmal -

<ScrollViewer Grid.RowSpan="1" Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="2" Name="scrollViewer">
    <Viewbox Margin="0"  MinWidth="400" MinHeight="500" 
        HorizontalAlignment="Left" VerticalAlignment="Top" Name="ViewBoxTestBuild">
        <Canvas x:Name="Camera1Canvas" telerikDragDrop:RadDragAndDropManager.AllowDrop="True" 
            Width="1200" Height="768" MouseLeftButtonDown="Camera1Canvas_MouseLeftButtonDown">
            <Image x:Name="Camera1Image" Source="timemagadj.jpg" Canvas.ZIndex="-1"  
                  HorizontalAlignment="Left" VerticalAlignment="Top" />
            <local:Three_Line_Graphic x:Name="threeLineEditTool" 
                  HorizontalAlignment="Left" Canvas.Left="594" Canvas.Top="621" />
            <l:Adorner x:Name="adorn" Canvas.ZIndex="100" />
        </Canvas>
    </Viewbox>
</ScrollViewer>

c# code -

private void Camera1Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var sendingObj = sender as Canvas;
            if (sendingObj == null) return;
            foreach (UserControl l in VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), sendingObj))
                {
                    if (l.Parent == Camera1Canvas )
                    {
                        adorn.AdornedElement = l as FrameworkElement;
                        adorn.adorned_MouseLeftButtonDown(l, e);
                        break;
                    }
                }
             base.OnMouseLeftButtonDown(e);
        }

My problem is that when VisualTreeHelper.FindElementsInHostCoordinates is called on left mouse click event, it returns no elements when I click on any object. I sure that it is a coordinate mapping issue, but as this is new ground for me, I'm unsure how to fix it.

A: 

You need to change your VisualTreeHelper line to

GeneralTransform transform = sendingObj.TransformToVisual(Application.Current.RootVisual);
Point pnt = transform.Transform(e.GetPosition(sendingObj));
var elements = VisualTreeHelper.FindElementsInHostCoordinates(pnt,Application.Current.RootVisual);
Stephan
@Stephan - Your suggestion still returns no elements.
photo_tom
Edited to show another way. The SL coordinate system is a little funky and has several quirks.
Stephan
@Stephan - that worked great with one modification: " VisualTreeHelper.FindElementsInHostCoordinates(pnt,sendingObj);"
photo_tom
A: 

Maybe in your case there is no need to use the VisualTreeHelper method.

Since you control the elements inside the canvas and you know their type, you can try something like this:

private void Camera1Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var sendingObj = sender as Canvas;
        if (sendingObj == null) return;
        foreach (UserControl l in sendingObj.Children)
            {
                var position = e.GetPosition(l);
                var lArea = new Rect(0,0,l.ActualWidth,l.ActualHeight);
                if (lArea.Contains(position))
                {
                    adorn.AdornedElement = l as FrameworkElement;
                    adorn.adorned_MouseLeftButtonDown(l, e);
                    break;
                }
            }
         base.OnMouseLeftButtonDown(e);
    }

Which is more efficient than hit-testing. However, this only works if rectangular areas are acceptable.

If you need to detect shapes other than rectangles, you can use the following, as long as you are filling a canvas with instances of UserControl:

private void Camera1Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var sendingObj = sender as Canvas;
        if (sendingObj == null) return;

        var elements = VisualTreeHelper
             .FindElementsInHostCoordinates(
                 e.GetPosition(sendingObj), sendingObj);

        foreach (var l in elements)
        {
            if (l is UserControl)
            {
                adorn.AdornedElement = l as FrameworkElement;
                adorn.adorned_MouseLeftButtonDown(l, e);
                break;
            }
        }
        base.OnMouseLeftButtonDown(e);
    }
Murven
@Murven - I like this answer, I'll use this at a later date. Thanks.
photo_tom