Change absolute positioning in Canvas from code - c#

I am creating my own usercontrol where I have a Canvas which will hold Hexagons.
I'm now at the stage where I'm adding the function AddItem, and since I don't want the hexagons to overlap I obviously want to use the Canvas' positioning methods. But how do I access them from "normal" code?
I have a Path object hexagon which holds the hexagon-data and I want to add it to my canvas aka container
So how do I change the positioning from c# code?
I know that in XAML my path looks like this when inside the Canvas (please notice Canvas.Left and Canvas.Top) , you'll have to scroll a bit..
<Canvas x:Name="Container" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<Path d:LayoutOverrides="None" d:LastTangent="0,0" Stroke="White" Fill="#343434" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" Width="50" Height="50" Stretch="Fill" Data="M8.660254,0 L17.320508,5 17.320508,15 8.660254,20 0,15 0,5 8.660254,0 z"/>
<Path d:LayoutOverrides="None" d:LastTangent="0,0" Stroke="White" Fill="#343434" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" Width="50" Height="50" Stretch="Fill" Data="M8.660254,0 L17.320508,5 17.320508,15 8.660254,20 0,15 0,5 8.660254,0 z" Canvas.Left="25" Canvas.Top="37.5"/>
</Canvas>

Use this method
Path myPath = ....; // obtain your path here
Canvas.SetLeft(myPath,25);
Canvas.SetTop(myPath,25);

Related

Zoom and move image with code

I have an image inside a border and I would like to show different parts of the image source in the image box at different times. Specifically, when a certain textbox gets focus, I want to change the image so it zooms to a certain portion of the image content.
Here's the XAML:
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="5" Height="504"
HorizontalAlignment="Left" Margin="20,116,0,0" Name="border1"
VerticalAlignment="Top" Width="410" ClipToBounds="True">
<Image Height="493" Name="image5" Stretch="Fill" Width="390"
ClipToBounds="True" BindingGroup="{Binding}"
Clip="{Binding ElementName=border1}"
Cursor="Hand" StretchDirection="Both" />
</Border>
For an example, my image source is 2550 x 3320 pixels. I would like the image box to show the source in a rectangle starting at point 1755,300 with width of 650 and height of 230. I do not want to use CloneBitmap to cut that rectangle out and display it because I also have a manual zoom set up for this image where the user can use the mouse wheel to zoom in and out and click & drag to pan the image. I still want to allow that after we zoom to desired area.
UPDATE:
I've tried implementing colinsmith's answer, but whenever I change the scrollviewer's offsets, It chops the image, so if I later move (click and drag to pan) it, it's empty space. I've had this working before with just the image inside the scrollviewer, but now I have an image inside a scrollviewer inside a border. The border is necessary for my zoom and pan as I have it set up now.
My updated XAML:
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="5" Height="504"
HorizontalAlignment="Left" Margin="20,116,0,0" Name="border1"
VerticalAlignment="Top" Width="410" ClipToBounds="True">
<ScrollViewer x:Name="image5scroll" VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Hidden">
<Image Height="493" Name="image5" Stretch="Fill" Width="390"
ClipToBounds="True" BindingGroup="{Binding}"
Clip="{Binding ElementName=image5scroll}" Cursor="Hand"
StretchDirection="Both" />
</ScrollViewer>
</Border>
And code behind:
public void imageZoom(Element element, int index)
{
if (element.Rectangle.Left - 100 > 0)
{
image5scroll.ScrollToHorizontalOffset(element.Rectangle.Left - 100);
image5scroll.Width = element.Rectangle.Width + 200;
image5scroll.Height = element.Rectangle.Height + 200;
border1.Width = image5scroll.Width;
border1.Height = image5scroll.Height;
image5.Width = image5scroll.Width;
image5.Height = image5scroll.Height;
image5.Stretch = System.Windows.Media.Stretch.None;
}
else
{
image5scroll.ScrollToHorizontalOffset(0);
}
if (element.Rectangle.Top - 100 > 0)
{
image5scroll.ScrollToVerticalOffset(element.Rectangle.Top - 100);
}
else
{
image5scroll.ScrollToVerticalOffset(0);
}
}
You can use a ScrollViewer to wrap your Image...then you can tell the ScrollViewer to go to a vertical and horizontal offset by calling the ScrollToVerticalOffset() and ScrollToHorizontalOffset() methods (as there isn't a property which you can set).
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="5" Height="504"
HorizontalAlignment="Left" Margin="20,116,0,0" Name="border1" VerticalAlignment="Top" Width="410">
<ScrollViewer x:Name="image5scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
<Image Height="493" Name="image5" Stretch="None" Width="390" BindingGroup="{Binding}"
Cursor="Hand" Source="http://www.noaanews.noaa.gov/stories/images/goes-12-firstimage-large081701.jpg"/>
</ScrollViewer>
</Border>
</Grid>
</Page>
However, if you must be be able to set the position of the ScrollViewer using properties instead of code-behind then a solution is to define an Attached Property which does the calls to ScrollToVerticalOffset/ScrollToHorizontalOffset for you underneath.
http://marlongrech.wordpress.com/2009/09/14/how-to-set-wpf-scrollviewer-verticaloffset-and-horizontal-offset/

cannot draw shape in canvas

I have a canvas in xaml defined as following. However adding a rectangle in it doesn't show any thing.
<lib:DrawingCanvas x:Name="drawingCanvas" Background="White" AllowDrop="True">
<Rectangle Margin="20,20,20,20" Fill="Black" Stroke="White" Width="100" Height="100">
</Rectangle>
</lib:DrawingCanvas>
Can you give me some hints here?
Thanks.
You're not using a Canvas, you're using a "DrawingCanvas", so I can't speak for any differences. But assuming it derives from Canvas:
You need to set the attached properties for the Rectangle. These are Canvas.Left or Canvas.Right, in addition to Canvas.Top or Canvas.Bottom.
For example:
<Rectangle Canvas.Left="50" Canvas.Top="100" Width="100" Height="100" Fill="Black" />

Prevent image crop when rotating using transform

I'm binding following XAML to RotateAngle property and it works great with one "but". Image displays cropped. Image control doesn't seem to be refreshing/resizing after rotation. Is there any way to force resize on image and scrollviewer?
<ScrollViewer Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" BorderThickness="0" HorizontalScrollBarVisibility="Auto">
<Image
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding Input, Converter={StaticResource ByteArrayToBitmapConverter}}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding RotateAngle}"></RotateTransform>
</Image.RenderTransform>
</Image>
</ScrollViewer>
http://www.silverlight.net/content/samples/sl3/toolkitcontrolsamples/run/default.html
Go to this page, there is a control called LayoutTransformer. See the sample of that control. It handles rotation, scaling and skewing of images, textbox, listbox, etc.
You will get the code there.
Hope that helps.!
You can try:
<Image x:name="ctrl"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding Input, Converter={StaticResource ByteArrayToBitmapConverter}}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding DataContext.RotateAngle, ElementName=ctrl}"></RotateTransform>
</Image.RenderTransform>
</Image>
Or you can use:
<Image
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Source="{Binding Input, Converter={StaticResource ByteArrayToBitmapConverter}}"
RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding DataContext.RotateAngle, RelativeSource={RelativeSource Self}}"></RotateTransform>
</Image.RenderTransform>
</Image>
Assuming you want to scale your image down to fit the original image space, you could use my CalculateConstraintScale method from here:
Silverlight Rotate & Scale a bitmap image to fit within rectangle without cropping to scale the image down based on the rotation.
Click here for a working testbed app created for that answer (looks like the image below):

One circle and line inside it with radius 56

How to draw line inside circle, line will be visible only inside circle and I need to have control on line angel. Let say one circle and line inside it with angel 56. How to do this in C# WPF.
Just put an Ellipse and a Line in a Panel that lets them draw on top of each other (such as a Grid), and adjust the parameters to whatever you want.
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.LayoutTransform>
<RotateTransform Angle="56" CenterX="28" CenterY="28"/>
</Grid.LayoutTransform>
<Ellipse Height="56" Width="56" Stroke="Red" StrokeThickness="2" />
<Line X1="1" X2="55" Y1="28" Y2="28" Stroke="Red" StrokeThickness="2" />
</Grid>
If you want to do it in XAML, do it like this:
<Line X1="1" X2="55" Y1="28" Y2="28" Stroke="Red" StrokeThickness="2" >
<Line.LayoutTransform>
<RotateTransform Angle="56" CenterX="50" CenterY="50"/>
</Line.LayoutTransform>
</Line>
If you read through the respective overviews you should be able to manage: Geometry & Shapes

How to set Canvas.ZIndex to paint a black panel between the controls?

With the following code I can demonstrate how a black panel with a opacity of 50% is on top of every rectangle:
<Grid>
<Rectangle Fill="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.5" Canvas.ZIndex="1"/>
<Rectangle Fill="Red" Width="200" Height="200" Canvas.ZIndex="0"/>
<Grid>
<Rectangle Fill="Blue" Width="100" Height="100" Canvas.ZIndex="0"/>
<Rectangle Fill="Yellow" Width="50" Height="50" Canvas.ZIndex="1"/>
</Grid>
</Grid>
It looks like this:
I would like to have the yellow rectangle above the black panel, but that seems to be impossible.
I can achieve something close by setting the ZIndex of the Grid containing both the Blue and Yellow rectangles to "1". But this would also raise the blue rectangle above the black, and this is a problem.
<Grid>
<Rectangle Fill="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.5" Canvas.ZIndex="1"/>
<Rectangle Fill="Red" Width="200" Height="200" Canvas.ZIndex="0"/>
<Grid Canvas.ZIndex="1">
<Rectangle Fill="Blue" Width="100" Height="100" Canvas.ZIndex="0"/>
<Rectangle Fill="Yellow" Width="50" Height="50" Canvas.ZIndex="1"/>
</Grid>
</Grid>
How do I get only the yellow rectangle above the black?
In my real application I have user controls instead of the rectangles. I like to make a particular control standing out by having everything else covered by the half-black shade.
Many Thanks,
I don't think you'll be able to achieve this with your current arrangement of controls.
There are two levels of controls here, the "Blue" and "Yellow" controls inside the inner grid and then the "Black" and "Red controls together with the inner grid.
The ZIndex works on controls at the same "level" - so you can ensure that the yellow control is on top of the blue, but then at the higher level these are grouped under the inner grid so are treated as a single unit.
The only way this would work is if all your controls were at the same level. If you included a second semi opaque rectangle in the inner grid you could get the yellow to be on top of that but that might end up making other controls too dark.
One approach might be to not use just a simple black rectangle.
Instead use a Path composed of two rectangles. The first rectangle will cover the whole area and the second would just cover the control to be available.
This creates a large rectangle with a hole in it where your target control can show through and accept input.
The down side is working out the rectangle geometry to add to create the hole but that's fairly straight forward.

Categories

Resources