Quantcast
Channel: Windows Presentation Foundation (WPF) forum
Viewing all articles
Browse latest Browse all 18858

How do I two-way bind Rectangles on a canvas to a business model?

$
0
0

As a beginner, I spent a ton of time creating a canvas that you can draw rectangles on -- and then selecting a rectangle so you can move it around or resize it.

So I am pretty happy with how this works. But now I need to add the second part to it. Every rectangle represents a section on the screen (the black canvas represents the user's screen). So when the user draws a rectangle, I want to automatically create a new instance of class Section in my ViewModel's ObservableCollection<Section>.

Section.cs looks like this:

public class Section
    {
        public int SectionId { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public int X { get; set; }
        public int Y { get; set; }
        public SectionType SectionType { get; set; }

        [ForeignKey("Layout")]
        public int LayoutId { get; set; }   
        [ForeignKey("LayoutId")]
        public virtual Layout Layout { get; set; }
    }



My XAML looks like this:

<Canvas x:Name="LayoutCanvas"
                Grid.Row="2"
                Grid.ColumnSpan="2"
                Background="#FF2B2B2B"
                Loaded="Canvas_Loaded"
                MouseDown="Designer_MouseDown"
                MouseUp="Designer_MouseUp"
                MouseLeave="Designer_MouseLeave"
                MouseMove="Designer_MouseMove"/>

My Code-behind has all the mouse handlers:

private void Designer_MouseDown(object sender, MouseButtonEventArgs e) { if (e.Source != LayoutCanvas) { RemoveAdorners(e); } else { CreateNewSection(e); DeselectSection(); } } private void CreateNewSection(MouseButtonEventArgs e) { _startPoint = e.GetPosition(LayoutCanvas); _rect = new Rectangle { Fill = Brushes.Brown, Opacity = .8 }; Canvas.SetLeft(_rect, _startPoint.X); Canvas.SetTop(_rect, _startPoint.X); LayoutCanvas.Children.Add(_rect); }

private void Designer_MouseMove(object sender, MouseEventArgs e)
{
    if (!_isDown)
    {
        DrawSection(e);
    }
    else
    {
        MoveSection(e);
    }
}

private void MoveSection(MouseEventArgs e)
{
    if ((_isDragging == false) &&
        ((Math.Abs(e.GetPosition(LayoutCanvas).X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance) ||
            (Math.Abs(e.GetPosition(LayoutCanvas).Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)))
        _isDragging = true;

    if (_isDragging)
    {
        Point position = Mouse.GetPosition(LayoutCanvas);

        var newTop = position.Y - (_startPoint.Y - _originalTop);
        var newBottom = newTop + selectedElement.RenderSize.Height;
        var newLeft = position.X - (_startPoint.X - _originalLeft);
        var newRight = newLeft + selectedElement.RenderSize.Width;

        if (newTop >= 0 && newBottom <= LayoutCanvas.ActualHeight)
            Canvas.SetTop(selectedElement, newTop);

        if (newLeft >= 0 && newRight <= LayoutCanvas.ActualWidth)
            Canvas.SetLeft(selectedElement, newLeft);
    }
}

private void DrawSection(MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Released || _rect == null)
        return;

    var pos = e.GetPosition(LayoutCanvas);

    var x = Math.Min(pos.X, _startPoint.X);
    var y = Math.Min(pos.Y, _startPoint.Y);

    var w = Math.Max(pos.X, _startPoint.X) - x;
    var h = Math.Max(pos.Y, _startPoint.Y) - y;

    _rect.Width = w;
    _rect.Height = h;

    Canvas.SetLeft(_rect, x);
    Canvas.SetTop(_rect, y);
}

How do I two-way bind this? I want the Section instance to:

  1. Automatically be created if a rectangle is created
  2. Automatically be updated if a rectangle changes in size or position

What I have read is that I need to use ItemsControl to make this happen; with ItemsSource set to my ObservableCollection<Section>. I have tried, but failed.


Viewing all articles
Browse latest Browse all 18858

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>