在 WPF 上分层绘制矩形 Canvas
Drawing hierarchically Rectangle on WPF Canvas
我正在尝试将 rectangles
放在下一张图片中
蓝色箭头显示 child
中的 parent-element
。
我得到了一个名为 Box
的 class,它有一个 Box 的父属性。
我将所有创建的 Boxes 推入 ObservableCollection
以用于 XAML 代码中的绑定。
这是盒子 class:
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; }
}
但是现在我没有像图片中那样在 canvas 上绘制矩形的正确方法。我想创建一个具有不同列数量的网格,但我不确定这是否可行。
此致。
如果您想在 Canvas 中绘制矩形只是为了布局目的,利用 WPF 的面板会容易得多。要使用 ObservableCollection 的完整绑定,需要大量编码。所以下面是一个简单的例子。
盒子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 继承自 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;
}
}
主窗口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));
}
}
}
我正在尝试将 rectangles
放在下一张图片中
蓝色箭头显示 child
中的 parent-element
。
我得到了一个名为 Box
的 class,它有一个 Box 的父属性。
我将所有创建的 Boxes 推入 ObservableCollection
以用于 XAML 代码中的绑定。
这是盒子 class:
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; }
}
但是现在我没有像图片中那样在 canvas 上绘制矩形的正确方法。我想创建一个具有不同列数量的网格,但我不确定这是否可行。
此致。
如果您想在 Canvas 中绘制矩形只是为了布局目的,利用 WPF 的面板会容易得多。要使用 ObservableCollection 的完整绑定,需要大量编码。所以下面是一个简单的例子。
盒子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 继承自 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;
}
}
主窗口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));
}
}
}