1

Can someone please help me with my problem. I am creating a program that can draw a rectangle on an Image. I am using WPF and MVVM Pattern.

The requirement is. The viewer can zoom and pan the image. Draw rectangle with resize and move the drawn rectangle.

Then I found this answer from the link below

Pan & Zoom Image

I implemented the ZoomBorder class from the answer.

Then because I also need to draw rectangle. I modified the code and added Dependency Property that returns Rect

        public Rect Rect
        {
            get { return (Rect)GetValue(RectProperty); }
            set { SetValue(RectProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Rect.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RectProperty =
            DependencyProperty.Register("Rect", typeof(Rect), typeof(ZoomBorder),
                new FrameworkPropertyMetadata(new Rect(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null));

And this is how i use it

<Viewer:ZoomBorder x:Name="img" Rect="{Binding Rect}" IsDraw="{Binding IsDraw}">

            <Grid>

                <Image Height="{Binding ActualHeight, ElementName=img, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ActualWidth, ElementName=img, UpdateSourceTrigger=PropertyChanged}" Stretch="None" Source="img_05_l.jpg"/>
                <ItemsControl ItemsSource="{Binding RectItems}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas  x:Name="canvas" Background="Transparent"  Height="{Binding ActualHeight, ElementName=img, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ActualWidth, ElementName=img, UpdateSourceTrigger=PropertyChanged}" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemContainerStyle>
                        <Style TargetType="{x:Type ContentPresenter}">
                            <Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                            <Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

                        </Style>
                    </ItemsControl.ItemContainerStyle>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Rectangle Width="{Binding Width}"
                                       Height="{Binding Height}" 
                                       Fill="Transparent" 
                                       Stroke="Blue" 
                                       StrokeThickness="1"  />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>

            </Grid>
        </Viewer:ZoomBorder>

Then I have a working pan zoom and drawing. But I still need the resize and move the drawn rectangle.

Then after hours of searching I found this blog which resize and move the objects in the canvas

http://www.voidcn.com/article/p-krlsqrhc-uw.html

but my problem is. I can't select the drawn rectangle in canvas.

Here is the code for selecting the control in the canvas

// Handler for element selection on the canvas providing resizing adorner
        void myCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Remove selection on clicking anywhere the window
            if (selected)
            {
                selected = false;
                if (selectedElement != null)
                {
                    // Remove the adorner from the selected element
                    aLayer.Remove(aLayer.GetAdorners(selectedElement)[0]);                    
                    selectedElement = null;
                }
            }

            // If any element except canvas is clicked, 
            // assign the selected element and add the adorner
            if (e.Source != myCanvas)
            {
                _isDown = true;
                _startPoint = e.GetPosition(myCanvas);

                selectedElement = e.Source as UIElement;

                _originalLeft = Canvas.GetLeft(selectedElement);
                _originalTop = Canvas.GetTop(selectedElement);

                aLayer = AdornerLayer.GetAdornerLayer(selectedElement);
                aLayer.Add(new ResizingAdorner(selectedElement));
                selected = true;
                e.Handled = true;
            }
        }

But my problem is how can I select the drawn rectangle? The problem is the control selected is the Grid not the Canvas - how can I solve this problem?

If I'm going to remove the Grid. I will have an error "the property Child is set more than once". I need both of the canvas and the image. I can't find a solution so I decided to ask here.

dymanoid
  • 14,771
  • 4
  • 36
  • 64
classname13
  • 123
  • 3
  • 13

1 Answers1

0

The way that markup works is you present a collection of viewmodels ( or whatever they are ) as RectItems to the itemscontrol.

Each of those is templated into a rectangle.

If you want to remove one then take it's viewmodel out RectItems. Assuming it's an observablecollection then it'll notify the collection changed and the rectangle will be removed.

The specific RectItem will be the datacontext of selectedElement when you do:

 selectedElement = e.Source as UIElement;

So grab it's datacontext and cast it to whatever a RectItem is.

Then get a reference to the viewmodel where RectItems is. Maybe that's the datacontext of the window. You can then use .Remove() on RectItems to take it out.

Andy
  • 11,864
  • 2
  • 17
  • 20