在WPF Canvas上按层次结构绘制矩形

时间:2015-01-18 15:26:31

标签: c# wpf xaml canvas hierarchical

我试图将rectangles放在下一张图片中

enter image description here

蓝色箭头显示parent-element的{​​{1}}。

我找到了一个名为child的班级,其中包含一个家庭财产。 我为XAML代码中的绑定推送了Box所有创建的Box。

这是Box类:

ObservableCollection

但是现在我没有得到一个正确的方法来绘制画布上的矩形。我有了创建一个具有不同列数的网格的想法,但如果可能的话,我并不是真的。

最好的问候。

1 个答案:

答案 0 :(得分:0)

如果你想在画布中绘制矩形只是为了布局目的,利用WPF的面板会更容易。要使用与ObservableCollection的完全绑定,需要大量编码。以下是一个简单的例子。

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类继承自StackPanel

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

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>

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 screenshot