Why does the functional Panel.SetZIndex() not work in my code? - c#

Good evening! I'm trying to set SetZIndex for a childe element in a XAML layout. I found information about the Panel.SetZIndex and Canvas.SetZIndex. If I'm not mistaken, it's the same thing, but a Canvas.SetZIndex is older then Panel.SetZIndex.
So, the code below is my XAML layout
<Window x:Class="MLvisualisator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MLvisualisator"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="50px"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
<TextBox Name="CCountOfNeyrons" Width="200" Margin="10" BorderBrush="Aqua"></TextBox>
<TextBox Name="CountOfColum" Width="200" Margin="10" BorderBrush="Aqua"></TextBox>
<Button Name="Generate" Content="Generate" Click="GenerateFun"/>
</StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Grid.Column="0" Grid.Row="1">
<Canvas Name="TestAdd">
//there will be child elements
</Canvas>
</ScrollViewer>
</Grid>
</Window>
My class, where I created an Ellipse as a child element
...
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(28, 28, 28, 0);
Ellipse ell = new Ellipse
{
Width = sc.NeuronRadius,
Height = sc.NeuronRadius,
Fill = mySolidColorBrush,
Name = id
};
Canvas.SetLeft(ell, columCanvas);
Canvas.SetTop(ell, rowCanvas);
Panel.SetZIndex(ell, 2); // It doesn't work, and I don't know why
TestAdd.Children.Add(ell);
...
Later I did the same with Lines:
...
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(120, 255, 0, 0);
Line line = new Line // x1, x2, y1, y2, sc.NeuronRadius are an integer params
{
X1 = x1 + (sc.NeuronRadius / 2),
X2 = x2 + (sc.NeuronRadius / 2),
Y1 = y1 + (sc.NeuronRadius / 2),
Y2 = y2 + (sc.NeuronRadius / 2),
Name = "W" + start + "_" + end,
StrokeThickness = 4,
Stroke = mySolidColorBrush,
};
TestAdd.Children.Add(line);
Panel.SetZIndex(line, 0); // It doesn't work, and I don't know why
...
The result is this picture
But I want the lines to be under the Ellipses
Where did I made a mistake?

The Lines are actually drawn below the Ellipses.
That is however not very obvious because you are drawing both shape types with semi-transparent Brushes.
To make this clear, write for example
Ellipse ell = new Ellipse
{
Fill = Brushes.LightGray,
...
};
and
Line line = new Line
{
Stroke = Brushes.Red,
...
};
The first parameter of the Color.FromArgb method is an alpha value, i.e. an opacity. A value of 0 means fully transparent, while 255 means fully opaque.

Related

annotated drawing must remain same position where it was done in WPF

i used WPF application and i have drawn a line on a dicom image.but my problem is when i resize main window, line positions are changed. it wont persist on the place where i drawn. i have tried with pointtoscreen method and translatepoint method. but didnt work. what is the correct way to do this.
i used two wpf image controls. one is to display the dicom image and other is on top of it to draw annotation.following is my wpf xaml code.
<Border x:Name="Border" ClipToBounds="True">
<Grid>
<Image x:Name="ImageTileViewer"
Margin="-234"
Source="{Binding CurrentImage}"
Stretch="None"
StretchDirection="DownOnly" RenderTransformOrigin="0.5,0.5"/>
<Grid Name="AnnotationImageGrid">
<Image Name="AnnotationImage" Stretch="None" RenderTransformOrigin="0.5,0.5"/>
</Grid>
</Grid>
<Grid>
<Canvas Name="canDrawing" Height="450" Width="800"
MouseMove="canDrawing_MouseMove_NotDown"
MouseDown="canDrawing_MouseDown">
<Image Name="imgTrash"
StretchDirection="DownOnly" RenderTransformOrigin="0.5,0.5"
Source="C:\Users\Chaithika\Downloads\after_resize.PNG" />
</Canvas>
</Grid>
public Window1()
{
InitializeComponent();
TransformGroup group = new TransformGroup();
ScaleTransform xform = new ScaleTransform();
group.Children.Add(xform);
TranslateTransform tt = new TranslateTransform();
group.Children.Add(tt);
imgTrash.RenderTransform = group;
canDrawing.RenderTransform = group;
}
private void Window1_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
var width = Convert.ToInt32(e.NewSize.Width);
var height = Convert.ToInt32(e.NewSize.Height);
double factor = Math.Min((width / imgTrash.ActualWidth), (height / imgTrash.ActualHeight));
if (width >= imgTrash.ActualWidth && height >= imgTrash.ActualHeight)
{
factor = 1;
}
TransformGroup transformGroup = (TransformGroup)imgTrash.RenderTransform;
ScaleTransform st = (ScaleTransform)transformGroup.Children[0];
st.ScaleX = factor;
st.ScaleY = factor;
TransformGroup transformGroup2 = (TransformGroup)canDrawing.RenderTransform;
ScaleTransform st2 = (ScaleTransform)transformGroup2.Children[0];
st2.ScaleX = factor;
st2.ScaleY = factor;
}

WPF How to get Width of a Panel dynamically

Hi I have an empty Panel, and want to add items to it at runtime. I also want to make sure that panel's Width doesn't extend the window's Width, If so I want o add items in other panel.
In my XAML :
<Border Grid.Row="1" Margin="5,0,5,0" Padding="2" Background="LightYellow"
BorderBrush="SteelBlue" BorderThickness="1" CornerRadius="3" >
<StackPanel Name="legendsPanel" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<DockPanel Name="legendsPnl1">
</DockPanel>
<DockPanel Name="legendsPnl2">
</DockPanel>
</StackPanel>
</Border>
In code behind :
int legendSize = 30; // W for 1 Legend
private void AddLegend(string title, double value, Brush clr)
{
MessageBox.Show("SP - " + legendsPanel.ActualHeight.ToString() + " DP - " + legendsPnl1.ActualHeight.ToString()); // 0, 0
Rectangle rect = new Rectangle();
rect.Width = 10; rect.Height = 10; rect.Fill = clr;
Label lbl = new Label();
lbl.Content = title + value;
/*
* Here, before adding to legendsPnl1 I want to make sure that it's W = (W + legendSize) <= legendsPanelWidth
* legendsPanel - > StackPanel i.e. Parent of legendsPnl1
* Width of legendsPanel, Grid, Window all are in wither Stretch mode or free Width - Auto or *,
* so can't make out how to get the W of them. At runtime, their W, ActualWidth are shown either 0, NaN, null
*/
legendsPnl1.Children.Add(rect);
legendsPnl1.Children.Add(lbl);
}
How to find legendsPnl1 panel hasenough space to add both elements (of size legendSize var ) , else add the elements in legendsPnl1 panel ????
Thanks

Strange behavior during movement of UIElement. Why?

I'm having some trouble understanding (and fixing) a bug I'm experiencing.
I have the UI like in the following picture:
All of those areas colored in lightblue are Canvases and they are movable. This is where I have my problem. The one from the top left can be moved without problems. The other two, when I'm dragging them, disappear. I can't explain why.
This is the code for the moving of elements:
// this is all inside the MouseMove event handler function
// If there is no dragged element
if (this.DraggedElement == null || !this.IsDragInProgress)
return;
/*
* Calculating the new position for the dragged element
*/
// Mouse current position
Point cursor = e.GetPosition(this);
double xMove = 0;
double yMove = 0;
// Movement detected
if (cursor != MouseClickLocation)
{
// Moving on the x-axis and y-axis
xMove = cursor.X - MouseClickLocation.X;
yMove = cursor.Y - MouseClickLocation.Y;
// Actually moving the element
if (this.ConstrainToBounds(this.DraggedElement, mainWindow))
{
TranslateTransform translate = new TranslateTransform(xMove, yMove);
this.DraggedElement.RenderTransform = translate;
}
}
The code for ConstrainToBounds() method is supposed to not allow me to move any Canvas outside the window borders (it works perfectly for the top left Canvas, but not for the others) and is as follows:
private Boolean ConstrainToBounds(Canvas element, UIElement container)
{
try
{
Boolean respects = true;
// Values used to reset the element position to a proper location
double xReset = 0;
double yReset = 0;
// Left x-axis constraint
if (element.TranslatePoint(new Point(), container).X <= new Point(0, 0).X)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X + 1;
yReset = element.TranslatePoint(new Point(), container).Y;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Right x-axis constraint
if (element.TranslatePoint(new Point(), container).X + element.RenderSize.Width >= container.RenderSize.Width)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X - 1;
yReset = element.TranslatePoint(new Point(), container).Y;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Top y-axis constraint
if (element.TranslatePoint(new Point(), container).Y <= new Point(0, 0).Y)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X;
yReset = element.TranslatePoint(new Point(), container).Y + 1;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Bottom y-axis constraint
if (element.TranslatePoint(new Point(), container).Y + element.RenderSize.Height >= container.RenderSize.Height)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X;
yReset = element.TranslatePoint(new Point(), container).Y - 1;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
return respects;
}
catch (Exception ex)
{
throw ex;
}
}
Edit_1: Added code from MainWindow.xaml:
<Window
Name="mainWindow"
x:Class="WPF_TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="480" Width="555">
<Grid Name="mainGrid">
<Canvas Grid.Row="0"
Grid.Column="0"
Background="AliceBlue"
Name="LeftTop"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp" >
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Canvas Grid.Row="0"
Grid.Column="2"
Background="AliceBlue"
Name="RightTop"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp">
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Label Grid.Row="2"
Grid.Column="0"
Name="LeftBottom">
</Label>
<Canvas Grid.Row="2"
Grid.Column="3"
Background="AliceBlue"
Name="RightBottom"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp">
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="50" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Edit_2: So, I've discovered that when I move the top right canvas, it actually moves outside of the view (at position 600,0). Currently trying to understand why this happens.
Instead of using render transforms, might be easier to update the Canvas's Margin property:
if (cursor != MouseClickLocation)
{
// Moving on the x-axis and y-axis
xMove = cursor.X - MouseClickLocation.X;
yMove = cursor.Y - MouseClickLocation.Y;
// Actually moving the element
this.DraggedElement.Margin = this.CalculateNewPosition(this.DraggedElement, mainWindow, xMove, yMove);
}
Where CalculateNewPosition might look something like this (warning, untested):
private Thickness CalculateNewPosition(Canvas element, UIElement container, double translationX, double translationY)
{
Thickness currentPosition = element.Margin;
Thickness newPosition = new Thickness(currentPosition.Left + translationX, currentPosition.Top + translationY, 0, 0);
int containerWidth = container.ActualWidth;
int containerHeight = container.ActualHeight;
int elementWidth = element.ActualWidth;
int elementHeight = element.ActualHeight;
if (newPosition.Left < 0)
newPosition.Left = 0;
else if (newPosition.Left + elementWidth > containerWidth)
newPosition.Left = containerWidth - elementWidth;
if (newPosition.Top < 0)
newPosition.Top = 0;
else if (newPosition.Top + elementHeight > containerHeight)
newPosition.Top = containerHeight - elementHeight;
return newPosition;
}
I'm not sure why specifically your code isn't working for the other circles. Possibly it has to do with the bounds checks like:
if (element.TranslatePoint(new Point(), container).X <= new Point(0, 0).X)
if (element.TranslatePoint(new Point(), container).X + element.RenderSize.Width >= container.RenderSize.Width)
The assumption is that the new Point(0,0) and TranslatePoint are returning points relative to each containing grid cell. I'm not sure if that assumption is correct; one (or both) of the comparisons may be absolute with respect to the application or something to that effect. It would be difficult to ascertain exactly just via a cursory examination of your code; you would need to run the debugger and check your values and see where they diverge from what you expect.

WPF How to check if in canvas is empty spaces

I am adding rectangles on a Canvas using Random because I don't know the width and height.
Code
HProDataContext db = new HProDataContext();
var RoomX = (from d in db.rooms select d.sizex).ToList();
var RoomY = (from d in db.rooms select d.sizey).ToList();
var random = new Random();
for (int i = 0; i < RoomX.Count; i++)
{
RoomX[i] = (Convert.ToDouble(RoomX[i]) * 10).ToString();
RoomY[i] = (Convert.ToDouble(RoomY[i]) * 10).ToString();
var rectangle = new Rectangle()
{
Stroke = Brushes.Black,
Fill = Brushes.SkyBlue,
Width = Convert.ToDouble(RoomX[i]),
Height = Convert.ToDouble(RoomY[i]),
Margin = new Thickness(
left: random.NextDouble() * 300,
top: random.NextDouble() * 150,
right: 0,
bottom: 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
mainCanvas.Children.Add(rectangle);
}
}
It works good, but some rectangles are drawing over another rectangles.
How to draw rectangles there where is empty space?
You can calculate a Rect for each WPF Rectangle and use IntersectsWith method found in Rect to test if the code can a draw a new Rectangle without overlaps. I also recommend using rectangle properties Canvas.Left and Canvas.Top instead of adjusting the Margin.
I've included a simple example that you test to get you started.
Here is some XAML containing 4 Rectangles:
<Window x:Class="OverlapRectangeTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<Canvas x:Name="c" Grid.Row="0">
<Rectangle x:Name="b1" Fill="Aqua" Canvas.Left="0" Canvas.Top="0" Width="100" Height="200"/>
<Rectangle x:Name="b2" Fill="Bisque" Canvas.Left="0" Canvas.Top="0" Width="200" Height="100"/>
<Rectangle x:Name="b3" Fill="BlueViolet" Canvas.Left="250" Canvas.Top="0" Width="100" Height="200"/>
<Rectangle x:Name="b4" Fill="Cornsilk" Canvas.Left="111" Canvas.Top="0" Width="100" Height="200"/>
</Canvas>
<Button Grid.Row="1" Click="Button_Click"/>
</Grid>
</Window>
Here is a button click event handler where I test the IntersectsWith method:
private void Button_Click(object sender, RoutedEventArgs e)
{
double top1 = (double)b1.GetValue(Canvas.TopProperty);
double left1 = (double)b1.GetValue(Canvas.LeftProperty);
Rect rect1 = new Rect(left1, top1, b1.Width, b1.Height);
double top2 = (double)b2.GetValue(Canvas.TopProperty);
double left2 = (double)b2.GetValue(Canvas.LeftProperty);
Rect rect2 = new Rect(left2, top2, b2.Width, b2.Height);
double top3 = (double)b3.GetValue(Canvas.TopProperty);
double left3 = (double)b3.GetValue(Canvas.LeftProperty);
Rect rect3 = new Rect(left3, top3, b3.Width, b3.Height);
double top4 = (double)b4.GetValue(Canvas.TopProperty);
double left4 = (double)b4.GetValue(Canvas.LeftProperty);
Rect rect4 = new Rect(left4, top4, b4.Width, b4.Height);
bool rc0 = rect1.IntersectsWith(rect4);
bool rc1 = rect1.IntersectsWith(rect2);
bool rc2 = rect2.IntersectsWith(rect3);
bool rc3 = rect3.IntersectsWith(rect1);
bool rc4 = rect2.IntersectsWith(rect4);
}

WPF: How to draw UML interface relationship arrow?

I want to draw the following arrow type:
How can I do that?
I have already a similar arrow:
private void InternalDrawArrowGeometry(StreamGeometryContext context)
{
double theta = Math.Atan2(Y1 - Y2, X1 - X2);
double sint = Math.Sin(theta);
double cost = Math.Cos(theta);
Point pt1 = new Point(X1, this.Y1);
Point pt2 = new Point(X2, this.Y2);
Point pt3 = new Point(
X2 + (HeadWidth * cost - HeadHeight * sint),
Y2 + (HeadWidth * sint + HeadHeight * cost));
Point pt4 = new Point(
X2 + (HeadWidth * cost + HeadHeight * sint),
Y2 - (HeadHeight * cost - HeadWidth * sint));
context.BeginFigure(pt1, true, false);
context.LineTo(pt2, true, true);
context.LineTo(pt3, true, true);
context.LineTo(pt4, true, true);
context.LineTo(pt2, true, true);
}
How can I change so that this isn't an arrow but a circle?
Use an Ellipse shape and a vertical Line (with HorizontalAlignment set to center) in a vertical StackPanel. That is:
<StackPanel>
<Ellipse HorizontalAlignment="Center" Height="10" Width="10"
Stroke="Black" />
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="0" Y2="10"
Stroke="Black" />
<Rectangle Width="40" Height="20" Stroke="Black"/>
</StackPanel>
I also threw a Rectangle in there to represent the class that implements the interface.

Categories