使用MVVM WPF调整绘制的Rectangle的大小

时间:2018-01-09 05:36:41

标签: c# wpf canvas mvvm

我创建了一个简单的程序,使用MVVM Pattern将Rectangle绘制到canvas。然后我需要调整绘制的矩形的大小

我一直在寻找一个代码如何调整大小然后我找到了这个博客

https://denisvuyka.wordpress.com/2007/10/15/wpf-simple-adorner-usage-with-drag-and-resize-operations/

此博客分享了解决方案,因此我下载了它。

然后在我的代码中实现

这是我的xaml

<Grid>
        <ItemsControl ItemsSource="{Binding RectItems, Source={x:Static local:Vm.instance}}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas x:Name="canvas" Background="Transparent" Height="{Binding ElementName=window}" Width="{Binding ElementName=window}" >
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="MouseDown">
                                <ei:CallMethodAction MethodName="MouseDownEvent" TargetObject="{x:Static local:Vm.instance}"/>
                            </i:EventTrigger>
                            <i:EventTrigger EventName="MouseMove">
                                <ei:CallMethodAction MethodName="MouseMoveEvent" TargetObject="{x:Static local:Vm.instance}"/>
                            </i:EventTrigger>
                            <i:EventTrigger EventName="PreviewMouseLeftButtonDown">
                                <ei:CallMethodAction MethodName="PreviewMouseLeftButtonDownEvent" TargetObject="{x:Static local:Vm.instance}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </Canvas>

                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle Width="{Binding Width}" Height="{Binding Height}" Fill="Transparent" Stroke="Red" StrokeThickness="1"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>

这是我的模特

public class RectItem : INotifyPropertyChanged
    {
        private double _x;
        public double X
        {
            get { return _x; }
            set
            {
                _x = value;
                RaisePropertyChanged("X");
            }
        }

        private double _y;
        public double Y
        {
            get { return _y; }
            set
            {
                _y = value;
                RaisePropertyChanged("Y");
            }
        }
        private double _width;
        public double Width
        {
            get { return _width; }
            set
            {
                _width = value;
                RaisePropertyChanged("Width");
            }
        }

        private double _height;
        public double Height
        {
            get { return _height; }
            set
            {
                _height = value;
                RaisePropertyChanged("Height");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

这是我的ViewModel

AdornerLayer aLayer;

        bool _isDown;
        bool _isDragging;
        bool selected = false;
        UIElement selectedElement = null;

        Point _startPoint;
        private double _originalLeft;
        private double _originalTop;
        //end of variable declaration for resizing

        public ObservableCollection<RectItem> RectItems { get; set; }
        private Point startPoint;
        public Vm()
        {
            RectItems = new ObservableCollection<RectItem>();
        }
        public void MouseDownEvent(object sender, MouseButtonEventArgs e)
        {
            startPoint = Mouse.GetPosition((IInputElement)sender);
        }
        public void MouseMoveEvent(object sender, MouseEventArgs e)
        {

            if (e.LeftButton == MouseButtonState.Released)
                return;
            if (selected) return;

            var pos = Mouse.GetPosition((IInputElement)sender);

            // Set the position of rectangle
            var x = Math.Min(pos.X, startPoint.X);
            var y = Math.Min(pos.Y, startPoint.Y);

            // Set the dimenssion of the rectangle
            var w = Math.Max(pos.X, startPoint.X) - x;
            var h = Math.Max(pos.Y, startPoint.Y) - y;


            if (RectItems.Count != 0)
            {
                var exist = RectItems.Where(xx => xx.X == x).LastOrDefault();
                if (exist != null)
                {
                    exist.Height = h;
                    exist.Width = w;
                }
                else
                {
                    RectItems.Add(new RectItem
                    {
                        X = x,
                        Y = y,
                        Height = h,
                        Width = w
                    });
                }
            }
            else
                RectItems.Add(new RectItem
                {
                    X = x,
                    Y = y,
                    Height = h,
                    Width = w
                });
        }

这是我调整大小的代码

 public void PreviewMouseLeftButtonDownEvent(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 != sender as Canvas)
            {
                _isDown = true;
                _startPoint = Mouse.GetPosition((IInputElement)sender);

                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;
            }
            Debug.WriteLine("Selected Value: " + selected);
        }

从我在博客上找到的解决方案。我删除了代码中的所有代码,然后离开了这个

// 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;
            }
        }

可以从顶部,左侧,右侧按钮调整绘制的控件。

但是我的代码。当我从左上角调整大小时。

它没有从那里调整大小。它做什么调整宽度和高度。不是矩形的左上角

这是绘制的矩形

enter image description here

当我从顶部调整大小时会发生这种情况。它调整了右下角而不是左上角

enter image description here

1 个答案:

答案 0 :(得分:1)

我认为如果您在没有任何修改的情况下使用它,则问题出在ResizingAdorner类中。无论绑定如何,该类都会直接修改关联元素的大小和Canvas坐标。这意味着当您拖动左上角时,元素的大小已正确更改(因为WidthHeight属性已被修改),但代码会尝试设置Canvas.LeftCanvas.Right并不起作用,因为整个Rectangle位于ContentPresenterItemsControl的项容器)内。只有ContentPresenter才能真正影响该职位,因为它是Canvas的直接子女。在Canvas.Left上设置Canvas.RightRectangle无效,因为没有Canvas可以访问这些值。

要解决此问题,您必须抓住RectItem类中的ResizingAdorner实例 - 可能使用DataContext

var rectItem = adornedElement.DataContext as RectItem;

现在,您可以修改rectItem属性,而不是WidthHeightCanvas.LeftCanvas.TopResizingAdorner的所有现有引用} class。