简体   繁体   English

在WPF画布上分层绘制矩形

[英]Drawing hierarchically Rectangle on WPF Canvas

I'm trying to place rectangles like in the next picture 我正在尝试像下一张图片一样放置rectangles

在此处输入图片说明

The blue arrows shows the parent-element from the child . 蓝色箭头显示来自childparent-element

I got a class named Box with a parent propertie to a Box. 我有一个名为Box的类,其中有Box的父属性。 All the created Boxes I push into an ObservableCollection for my bindings in the XAML code. 我将所有创建的Box放入XAML代码中用于绑定的ObservableCollection中。

Here is the Box class: 这是Box类:

public class Box
{
    public string Content { get; set; } //Content in the Box
    public double X { get; set; }       //For Canvas.Left propertie
    public double Y { get; set; }       //For Canvas.Right propertie
    public double Width { get; set; }
    public double Height { get; set; }
    public Box Parent { get; set; }
}

But now I dont get a correct way to draw the rectangles on a canvas like in the picture. 但是现在我没有正确的方法在画布上绘制矩形,如图所示。 I got the idea to create a grid with different column amount but I'm not shure if this is possible. 我想到了创建具有不同列数的网格的想法,但是我不确定是否有可能。

Best regards. 最好的祝福。

If you want to draw Rectangles in a Canvas just for layout purpose, it will be much easier by taking advantage of WPF's Panels. 如果仅出于布局目的在画布中绘制矩形,则可以利用WPF的面板轻松得多。 To use complete binding with ObservableCollection, a lot of coding is required. 要将完整的绑定与ObservableCollection结合使用,需要进行大量编码。 So the following is a simple example. 因此,以下是一个简单的示例。

Box Class 箱类

public class Box
{
  public int Id { get; private set; }
  public int ParentId { get; private set; }
  public string Content { get; private set; }

  public Box(string content, int id, int parentId)
  {
    this.Id = id;
    this.ParentId = parentId;
    this.Content = content;
  }
}

BoxPanel Class inherited from StackPanel 从StackPanel继承的BoxPanel类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

public class BoxPanel : StackPanel
{
  public int Id { get; private set; }

  private readonly Border topPanel;
  private readonly StackPanel bottomPanel;

  public BoxPanel()
  {
    topPanel = new Border();
    bottomPanel = new StackPanel { Orientation = Orientation.Horizontal };

    this.Children.Add(topPanel);
    this.Children.Add(bottomPanel);
  }

  public BoxPanel(Box box)
    : this()
  {
    Id = box.Id;

    topPanel.Child = new TextBlock
    {
      Text = box.Content,
      HorizontalAlignment = HorizontalAlignment.Center,
      VerticalAlignment = VerticalAlignment.Center,
      Padding = new Thickness(14),
      Foreground = Brushes.White,
    };
    topPanel.Background = (Id % 2 == 0) ? Brushes.Gray : Brushes.DarkGray;
    topPanel.BorderBrush = Brushes.Black;
    topPanel.BorderThickness = new Thickness(1);
  }

  protected override void OnInitialized(EventArgs e)
  {
    base.OnInitialized(e);

    this.Loaded += (_, __) => AdjustBottomPanel();
    this.LayoutUpdated += (_, __) => AdjustBottomPanel();
  }

  public IReadOnlyCollection<BoxPanel> ChildrenPanel
  {
    get { return bottomPanel.Children.Cast<BoxPanel>().ToArray(); }
  }

  public void AddChildPanel(BoxPanel child)
  {
    bottomPanel.Children.Add(child);
    AdjustBottomPanel();
  }

  private void AdjustBottomPanel()
  {
    if (!ChildrenPanel.Any())
      return;

    var childWidth = Math.Max((Double.IsNaN(this.Width) ? 0 : this.Width), this.ActualWidth)
      / ChildrenPanel.Count;

    foreach (var child in ChildrenPanel)
      child.Width = childWidth;
  }
}

XAML of MainWindow MainWindow的XAML

<Window x:Class="WpfBoxPanel.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Width="500" Height="240">
  <Grid x:Name="LayoutRoot"/>
</Window>

And code behind of MainWindow 和MainWindow后面的代码

using System.Collections.Generic;
using System.Linq;
using System.Windows;

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();

    boxPanelRoot = new BoxPanel();
    LayoutRoot.Children.Add(boxPanelRoot);

    this.Loaded += (_, __) => PopulateBoxPanel();
  }

  private readonly IList<Box> Boxes = new List<Box>
  {
    new Box("1st", 1, 0),
    new Box("2nd 1", 2, 1),
    new Box("2nd 2", 3, 1),
    new Box("3rd 1", 4, 2),
    new Box("3rd 2", 5, 2),
    new Box("3rd 3", 6, 3),
    new Box("4th 1", 7, 4),
    new Box("4th 2", 8, 5),
    new Box("4th 3", 9, 5),
    new Box("4th 4", 10, 6),
    new Box("4th 5", 11, 6),
  };

  private readonly BoxPanel boxPanelRoot;

  private void PopulateBoxPanel()
  {
    foreach (var box in Boxes)
    {
      var existingPanels = boxPanelRoot.GetDescendants() // See VisualTreeHelperExtensions.GetDescendants method of WinRT Xaml Toolkit
        .OfType<BoxPanel>()
        .ToArray();

      if (existingPanels.Any(x => x.Id == box.Id))
        continue;

      var parent = existingPanels.FirstOrDefault(x => x.Id == box.ParentId);
      if (parent == null)
        parent = boxPanelRoot;

      parent.AddChildPanel(new BoxPanel(box));
    }
  }
}

WpfBoxPanel屏幕截图

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM