在WPF中,如何在画布上自由绘制大量形状而无需网格

huangapple go评论70阅读模式
英文:

In WPF how to free drawing large collection of shapes in canvas without grid

问题

我需要允许用户单击画布,并每次创建一个矩形和8个文本框以输入矩形的尺寸。这些框将相对于矩形的边界进行定位。因此,将有一个列表数组,其中列表中的每个项都是这些框的集合。

画布可以让我正常绘制一个矩形。我找到的唯一合适的方法来动态收集这些框是使用 "Grid",如下所示:

var g1 = new Grid();
g1.Width = 100;
g1.Height = 100;
Canvas.SetLeft(g1, 10);
Canvas.SetTop(g1, 10);

Rectangle rectangle = new Rectangle
{
    Width = 20,
    Height = 30,
    Fill = red,
    StrokeThickness = 2,
    Stroke = Brushes.Black
};
Canvas.SetLeft(rectangle, 10);
Canvas.SetTop(rectangle, 10);

g.Children.Add(rectangle);
LayoutCanvas.Children.Add(g);

但如果我现在需要添加文本框,所有文本框都会移到网格的中心。

var txt = new TextBox();
txt.Text = "New Text1";
txt.Width = 30;
txt.Height = 30;
Canvas.SetLeft(txt, 20);
Canvas.SetTop(txt, 30);
g1.Children.Add(txt);

要修复这个定位问题,我需要使用以下代码:

g1.ColumnDefinitions.Add(new ColumnDefinition());
g1.RowDefinitions.Add(new RowDefinition());
g1.RowDefinitions.Add(new RowDefinition());
g1.RowDefinitions.Add(new RowDefinition());

但我的应用程序不需要网格中行和列的组织,需要它完全以形状为基础,而且最好甚至不需要XAML。我尝试了其他对象,如StackPanel,但它们都没有太大不同。

解决方案:

Grid DynamicGrid = new Grid();
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Stretch;
DynamicGrid.ShowGridLines = true;
DynamicGrid.Background = new SolidColorBrush(Colors.LightSteelBlue);

var c1 = new Canvas();
var c2 = new Canvas();

//--------------------- Canvas1 Children ---------------------
Rectangle c1Rectangle = new Rectangle
{
    Width = 100,
    Height = 100,
    Fill = new SolidColorBrush(Color.FromRgb(255, 0, 0)),
    StrokeThickness = 2,
    Stroke = Brushes.Black
};
Canvas.SetLeft(c1Rectangle, 0);
Canvas.SetTop(c1Rectangle, 0);

TextBlock c1Textbox = new TextBlock();
c1Textbox.Width = 50;
c1Textbox.Height = 50;
c1Textbox.Text = "Text1";
c1Textbox.FontSize = 14;
c1Textbox.FontWeight = FontWeights.Bold;
c1Textbox.Foreground = new SolidColorBrush(Colors.White);
c1Textbox.VerticalAlignment = VerticalAlignment.Top;
Canvas.SetLeft(c1Textbox, 10);
Canvas.SetTop(c1Textbox, 10);

//--------------------- Canvas2 Children ---------------------
Rectangle c2Rectangle = new Rectangle
{
    Width = 100,
    Height = 100,
    Fill = new SolidColorBrush(Colors.LightBlue),
    StrokeThickness = 2,
    Stroke = Brushes.Red
};
Canvas.SetLeft(c2Rectangle, 420);
Canvas.SetTop(c2Rectangle, 220);

TextBlock c2Textbox = new TextBlock();
c2Textbox.Width = 50;
c2Textbox.Height = 50;
c2Textbox.Text = "Text2";
c2Textbox.FontSize = 14;
c2Textbox.FontWeight = FontWeights.Bold;
c2Textbox.Foreground = new SolidColorBrush(Colors.Black);
c2Textbox.VerticalAlignment = VerticalAlignment.Top;
Canvas.SetLeft(c2Textbox, 440);
Canvas.SetTop(c2Textbox, 240);

c1.Children.Add(c1Rectangle);
c1.Children.Add(c1Textbox);
c2.Children Add(c2Rectangle);
c2.Children.Add(c2Textbox);

DynamicGrid.Children.Add(c1);
DynamicGrid.Children.Add(c2);

this.Content = DynamicGrid;
this.Show();
英文:

I have a need to allow users to click on the canvas and create each time a rectangle and 8 textboxes to input the dimension of the rectangle. The boxes will be positioned relatively to the rectangle borders. So, there will be an array of List where each item in the list is a collection of those boxes.
The canvas can let me draw a rectangle normally. The only suitable way I found to collect those dynamically is the "Grid" like so:

var g1 = new Grid();
g1.Width = 100;
g1.Height = 100;
Canvas.SetLeft(g1, 10);
Canvas.SetTop(g1, 10);

Rectangle rectangle = new Rectangle
{
	Width = 20,
	Height = 30,
	Fill = red,
	StrokeThickness = 2,
	Stroke = Brushes.Black
};
Canvas.SetLeft(rectangle, 10);
Canvas.SetTop(rectangle, 10);
	
g.Children.Add(rectangle);
LayoutCanvas.Children.Add(g);

But if I now need to add the boxes, all boxes go to the center of the grid.

var txt = new TextBox();
txt.Text = "New Text1";
txt.Width = 30;
txt.Height = 30;
Canvas.SetLeft(txt, 20);
Canvas.SetTop(txt, 30);
g1.Children.Add(txt);

To fix that positioning I would have to use:

g1.ColumnDefinitions.Add(new ColumnDefinition());
g1.RowDefinitions.Add(new RowDefinition());
g1.RowDefinitions.Add(new RowDefinition());
g1.RowDefinitions.Add(new RowDefinition());

But my app doesn't need this organization of rows and columns in a grid and need it to be fully shapes and fully dynamical, preferably without even a XAML. I tried the other objects like StackPanel but they are all not much different.

SOLUTION:
I have this code that works now:

Grid DynamicGrid = new Grid();
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Stretch;
DynamicGrid.ShowGridLines = true;
DynamicGrid.Background = new SolidColorBrush(Colors.LightSteelBlue);

var c1 = new Canvas();
var c2 = new Canvas();

//--------------------- Canvas1 Children --------------------->
Rectangle c1Rectangle = new Rectangle
{
	Width = 100,
	Height = 100,
	Fill = new SolidColorBrush(Color.FromRgb(255, 0, 0)),
	StrokeThickness = 2,
	Stroke = Brushes.Black
};
Canvas.SetLeft(c1Rectangle, 0);
Canvas.SetTop(c1Rectangle, 0);

TextBlock c1Textbox = new TextBlock();
c1Textbox.Width = 50;
c1Textbox.Height = 50;
c1Textbox.Text = "Text1";
c1Textbox.FontSize = 14;
c1Textbox.FontWeight = FontWeights.Bold;
c1Textbox.Foreground = new SolidColorBrush(Colors.White);
c1Textbox.VerticalAlignment = VerticalAlignment.Top;
Canvas.SetLeft(c1Textbox, 10);
Canvas.SetTop(c1Textbox, 10);

//--------------------- Canvas2 Children --------------------->
Rectangle c2Rectangle = new Rectangle
{
	Width = 100,
	Height = 100,
	Fill = new SolidColorBrush(Colors.LightBlue),
	StrokeThickness = 2,
	Stroke = Brushes.Red
};
Canvas.SetLeft(c2Rectangle, 420);
Canvas.SetTop(c2Rectangle, 220);

TextBlock c2Textbox = new TextBlock();
c2Textbox.Width = 50;
c2Textbox.Height = 50;
c2Textbox.Text = "Text2";
c2Textbox.FontSize = 14;
c2Textbox.FontWeight = FontWeights.Bold;
c2Textbox.Foreground = new SolidColorBrush(Colors.Black);
c2Textbox.VerticalAlignment = VerticalAlignment.Top;
Canvas.SetLeft(c2Textbox, 440);
Canvas.SetTop(c2Textbox, 240);

c1.Children.Add(c1Rectangle);
c1.Children.Add(c1Textbox);
c2.Children.Add(c2Rectangle);
c2.Children.Add(c2Textbox);

DynamicGrid.Children.Add(c1);
DynamicGrid.Children.Add(c2);

this.Content = DynamicGrid;
this.Show();

答案1

得分: 1

尝试为每个对象创建一个画布,这将允许您自由定位每个对象:

Rectangle rectangle = new Rectangle
{
    Width = 20,
    Height = 30,
    Fill = red,
    StrokeThickness = 2,
    Stroke = Brushes.Black
};

var txt = new TextBox(){
    Text = "New Text1",
    Width = 30,
    Height = 30,
};

g1 = new Grid()
{
    Width = 100,
    Height = 100,
    Children =
    {
        new Canvas() { Children = { txt} },
        new Canvas() { Children = { rectangle} }
    }
};

Canvas.SetLeft(txt, 20);
Canvas.SetTop(txt, 30);
Canvas.SetLeft(rectangle, 10);
Canvas.SetTop(rectangle, 10);
英文:

Try creating a canvas per object, that should allow you to position each object freely:

Rectangle rectangle = new Rectangle
{
    Width = 20,
    Height = 30,
    Fill = red,
    StrokeThickness = 2,
    Stroke = Brushes.Black
};

var txt = new TextBox(){
    Text = "New Text1",
    Width = 30,
    Height = 30,
};

g1 = new Grid()
    {
    Width = 100,
    Height = 100,
            Children =
            {
                new Canvas() { Children = { txt} },
                new Canvas() { Children = { rectangle} }
            }
    };

Canvas.SetLeft(txt, 20);
Canvas.SetTop(txt, 30);
Canvas.SetLeft(rectangle, 10);
Canvas.SetTop(rectangle, 10);

huangapple
  • 本文由 发表于 2023年3月31日 19:50:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75898208.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定