WPF How to get Width of a Panel dynamically - c#

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

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 Image Cropping

I have a problem with image cropping. When I try to crop image with rectangle the cropping area is set to some strange value.
Here is xaml code:
<Grid Name="GridImage">
<Image Name="LoadedImage" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="HighQuality">
</Image>
<Canvas x:Name="ImageCanvas" ClipToBounds="True">
<Rectangle x:Name="SelectionRectangle" Stroke="LightBlue" Fill="#220000FF" Visibility="Collapsed" />
</Canvas>
</Grid>
and here how I crop image:
var imagePosition = LoadedImage.TransformToAncestor(GridImage).Transform(new Point(0, 0));
Rect rect1 = new Rect(Math.Max(Canvas.GetLeft(SelectionRectangle) - imagePosition.X, 0), Math.Max(Canvas.GetTop(SelectionRectangle) - imagePosition.Y, 0), SelectionRectangle.Width, SelectionRectangle.Height);
var ratioX = LoadedImage.Source.Width / LoadedImage.ActualWidth;
var ratioY = LoadedImage.Source.Height / LoadedImage.ActualHeight;
Int32Rect rcFrom = new Int32Rect
{
X = (int)(rect1.X * ratioX),
Y = (int)(rect1.Y * ratioY),
Width = (int)(rect1.Width * ratioX),
Height = (int)(rect1.Height * ratioY)
};
try
{
BitmapSource bs = new CroppedBitmap((BitmapSource)LoadedImage.Source, rcFrom);
LoadedImage.Source = bs;
SetImageStretch(LoadedImage);
SetElementVisibility(Visibility.Hidden, Visibility.Visible, SelectionRectangle);
}
private void SetImageStretch(Image image)
{
if (image.Source.Width > image.ActualWidth || image.Source.Height > image.ActualHeight)
image.Stretch = Stretch.Uniform;
else image.Stretch = Stretch.None;
}
Does anybody know how to fix that?
Here how it looks before cropping:
How it looks after cropping:
Most likely the problem is with image resolution, e.g. 300 dpi, versus screen resolution (most likely 96 dpi). Have you checked image's PixelWidth and PixelHeight?

How do I dynamically add and position CheckBox elements in WPF?

I started making a WinForms application to display a grid of 4×4×4 checkboxes, representing a real-life 43 grid of LEDs.
This is what it looks like right now:
I want to convert this to an WPF app, so that I can use the transparency option of the WPF Checkbox, to make the non-selected layer [there will be 4 layers] of checkboxes slightly transparent, to give it a more true 3D feeling.
I am new to WPF and I have tried to nest 2 elements in the main Window [for example, 2 grids to slightly overlap the position, by maybe 20 pixels, so that they would appear to be 3d-staggered], but it simply won't let me do that, and only lets me add a child grid inside the original grid.
TLDR: How can I dynamically create lots of checkboxes while giving them absolute pixel positions?
My current working WinForms C# code:
int spacing = 25;
int zero = 0;
for (int z = 1; z <= 4; z++)
{
List<string> zString = new List<string>();
for (int y = 1; y <= 4; y++)
{
for (int x = 1; x <= 4; x++)
{
int pixel_x = zero + ((x - 1) * spacing);
int pixel_y = (zero - 4) + ((y - 1) * spacing);
//int id = ((y - 1) * 4) + x;
CheckBox box = new CheckBox();
box.CheckStateChanged += new System.EventHandler(checkBox2_CheckedChanged);
box.Tag = id;
zString.Add(id.ToString());
//box.Text = id.ToString();
box.BackColor = Color.Transparent;
//box.
box.AutoSize = false;
box.Size = new Size(20, 20);
box.Padding = new Padding(3);
box.Location = new Point(pixel_x, pixel_y);
this.Controls.Add(box);
id++;
}
}
zero += 25;
}
Consider using an ItemTemplate ( or DataTemplate) to establish how each item will look within your viewmodel's collection.
Example:
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I would use multiple UniformGrids stacked on top of each other inside a regular grid (so they overlap). Each UniformGrid would have its Top and Left margins offset by a specific amount.
The item source of each UniformGrid would be bound to a list of Boolean properties on your view model for each "layer".
You can try this. Use a Canvas inside your Window.
<Window x:Name="myWindow1" x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Canvas x:Name="canvas" >
</Canvas>
Unlike Location available in Windows Forms, you can use Margin to set the position
int spacing = 100;
int zero = 0;
for (int z = 1; z <= 4; z++)
{
List<string> zString = new List<string>();
for (int y = 1; y <= 4; y++)
{
for (int x = 1; x <= 4; x++)
{
int pixel_x = zero + ((x - 1) * spacing);
int pixel_y = zero + ((y - 1) * spacing);
CheckBox box = new CheckBox();
Canvas.SetLeft(box, pixel_x);
Canvas.SetTop(box, pixel_y);
this.canvas.Children.Add(box);
}
}
zero = zero + 50;
}

Metro App (ScaleTransform) Content of ContentPresenter

I have a ContentPresenter and i try to scale the Content = ""(FrameworkElement)`.
Because if the Content.Size is to big it get cut off. I prepared these pictures to explain my problem.
We start from here. As you can see there is a part missing (yellow Panel is cuted).
So what I tried was ScaleTransform.
(XAML)
<ContentPresenter Content="SomeContent"
Grid.Row="1"
Grid.Column="0">
<ContentPresenter.RenderTransform>
<ScaleTransform ScaleX="0.75" ScaleY="0.75"></ScaleTransform>
</ContentPresenter.RenderTransform>
</ContentPresenter>
So after I added the ScaleTransform I got this result.
And obviously my Content got scaled, but its still cutted.
So I stopped to try it in XAML and this is what came out in c# .
public static FrameworkElement ScaleContent(FrameworkElement element, Size space)
{
ScaleTransform scaleTransform = new ScaleTransform();
double height = element.ActualHeight;
double width = element.ActualWidth;
if (height == 0 || width == 0)
{
element.Measure(new Size(space.Width,
space.Height));
element.Arrange(new Rect(0, 0, element.DesiredSize.Width, element.DesiredSize.Height));
height = element.ActualHeight;
width = element.ActualWidth;
}
double scaleWidth = space.Width / width;
double scaleHeight = space.width / height;
scaleTransform.ScaleX = scaleWidth;
scaleTransform.ScaleY = scaleHeight;
element.RenderTransform = scaleTransform;
return element;
}
And this is what came out.
To let you see the complete Example. I saved a Picture in a bigger Format, where the Content fits.
So what do you think is the problem ?
Thank you !

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.

Categories