Reputation: 6066
I am new to WPF. I am Adding Rectangle one after other on Canvas on Button Click. When i set the Height of Specific Rectangle from TextBox. It overlaps on Child Rectangle.
Eg:. When there are 3 Rectangles with Height=100
,Width=200
& when i set Height of Second Rectangle to 150
. then the Child Rectangle
must appear after the Second Rectangle & must not Overlap on Third Rectangle. Is it Possible?
static int val=0;
List<UIElement> itemstoremove = new List<UIElement>();
private void BtnAdd_Click(object sender, RoutedEventArgs e)
{
int heigt = 0;
int wegt = 0;
if (!string.IsNullOrEmpty(txtHeight.Text) && !string.IsNullOrEmpty(txtWidth.Text))
{
heigt = int.Parse(txtHeight.Text);
wegt = int.Parse(txtWidth.Text);
}
rect = new Rectangle();
rect.Stroke = Brushes.Red;
rect.StrokeThickness = 2;
rect.Height = heigt;
rect.Width = wegt;
Canvas.SetLeft(rect, 10);
Canvas.SetTop(rect, (rect.Height) * val);
rect.Tag = val;
canvasboard.Children.Add(rect);
val = val + 1;
//canvasboard is Canvas object
foreach (UIElement ui in canvasboard.Children)
{
if (ui.GetType() == typeof(Rectangle))
{
itemstoremove.Add(ui);
}
}
}
For Modifying the Height & Width:
private void BtnModify_Click(object sender, RoutedEventArgs e)
{
int heigt = 0;
int wegt = 0;
if (!string.IsNullOrEmpty(txtHeight.Text) && !string.IsNullOrEmpty(txtWidth.Text))
{
heigt = int.Parse(txtHeight.Text);
wegt = int.Parse(txtWidth.Text);
}
Rectangle rectToRemove;
foreach (UIElement ui in itemstoremove)
{
if (ui.GetType() == typeof(Rectangle) && ((Rectangle)ui).Tag.ToString() == txtModifyRect.Text)
{
rectToRemove = ui as Rectangle;
//itemstoremove.Remove(rectToRemove);
rectToRemove.Height = heigt;
rectToRemove.Width = wegt;
//canvasboard.Children.Remove(rectToRemove);
break;
}
}
}
This works fine. Just i want to Prevent Overlapping of Rectangle
on one another and must appear one after the other with Auto Adjusting.
Help Appreciated!
Upvotes: 1
Views: 1081
Reputation: 6066
Here is my solution:
<ScrollViewer VerticalScrollBarVisibility="Auto" Width="250" Height="500">
<WrapPanel Name="wrapboard" Orientation="Vertical" ></WrapPanel>
</ScrollViewer>
private void BtnAdd_Click(object sender, RoutedEventArgs e)
{
int heigt = 0;
int wegt = 0;
if (!string.IsNullOrEmpty(txtHeight.Text) && !string.IsNullOrEmpty(txtWidth.Text))
{
heigt = int.Parse(txtHeight.Text);
wegt = int.Parse(txtWidth.Text);
}
rect = new Rectangle();
rect.Stroke = Brushes.Red;
rect.StrokeThickness = 2;
rect.Height = heigt;
rect.Width = wegt;
rect.Tag = val;
wrapboard.Children.Add(rect);
val = val + 1;
//wrapboard is WrapPanel object
foreach (UIElement ui in wrapboard.Children)
{
if (ui.GetType() == typeof(Rectangle))
{
itemstoremove.Add(ui);
}
}
}
Upvotes: 0
Reputation: 33596
Does it need to be specifically Canvas
..? Even in pure WPF/Desktop there are some layout components that can do exactly this for you, compeltely automatically.
The behaviour of "stacking" the components one after another is exactly what StackPanel
class/component/control does:
<StackPanel x:Name="stacker" Orientation="Vertical">
<Rectangle Width="30" Height="100" Background="Green" />
<Rectangle Width="10" Height="50" Background="Blue" />
<Rectangle Width="20" Height="80" Background="Red" Margin="5,10" />
</StackPanel>
Note how the rectangles are positioned one under another according to their different Heights
. Note that I didn't have to specify Orientation=Vertical
, because the StackPanel's default behaviour is to position them like that. You can switch it to Horizontally if you like, and then it will stack them according to their Widths
. You can also fine-tune and add some extra spacing with i.e. Margin
as in the third rectange.
If you need to do it by code, then StackPanel
named stacker
is perfectly suited for it: you can add new elements to it dynamically and it will lay out the added ones just like it does with children defined in XAML: one under another.
With StackPanel you get even more! The StackPanel observes its children. If at some time after placing the children you change the heights/widths of the children, then StackPanel will instantly adjust the positions so none of them overlap (if you make the children smaller, it will squeeze them, if you make children large - it will expand etc).
If you really-really want to use Canvas
, then at the moment of adding-a-new-item, you will have to loop over the all existing-items stored in canvas, sum up their heights, and set the Y position of the new item to exactly that sum. That way, it will appear exactly under the last element. That's the most obvious way of doing that. However, it will not account for margins, spacings, and a few other fine details that may happen to be on your Canvas.
A better but less obvious way is to not sum up the heights again and again, but instead to position the new item according to the bottommost existing item. After all, all old items are positioned properly, right? But, what does bottommost
mean? Sometimes, a tall item positioned near the top may span further downwards than a not-so-tall item sitting at the center. Therefore, the bottommost
does not mean the item with maximum Y position
but means the item that has a furthest Bottom
, so the maximum Y+Height
. So:
Size.Height+Position.Bottom
is the largestPosition.Y
of the new item to that valueNow, you'll get roughly the same thing as StackPanel does - but it will be only a one-time effect. If you later modify the heights of some elements, you will have to recalculate all position and adjust all positions.. (*)
EDIT:
(*) I dont remember exactly, but if X/Y/Bottom properties are DependencyProperty, then you may even try to use Bindings for controlling the positions automatically. Tha might be quite fun thing to do on the Canvas. Just try binding the Y
of a latter element to a Bottom
of the former and it should all magically layout out them selves and even automatically update when moved/resized. Still, please try StackPanel first!
Upvotes: 1
Reputation: 31
In order to get the effect that you want you must change the Canvas to a WrapPanel. That way when you add the children to the canvas you don't add the location, it arranges the objects on its own. Basically you want this
<ScrollViewer VerticalScrollBarVisibility="Auto" >
<WrapPanel Name="objList" > </WrapPanel>
</ScrollViewer>
The ScrollViewer will let you scroll if you have more objects than the window can contain.
Upvotes: 1
Reputation: 31
Sounds like you want a StackPanel
for your rectangles. You can have the StackPanel nested in your Grid.
Upvotes: 0