How can I prevent WPF from clipping my image? - wpf

I am writing a WPF app that displays an image that is initially centered. The user can zoom in/out and move the image, which are implemented using ScaleTransform and TranslateTransform. That works great.
The problem is when the image is significantly bigger than the window, and the user moves the image or zooms out enough so that the entire image should be visible. The portion of the image that was originally hidden isn't rendered, and instead only the originally viewable part of the image is drawn.
Based on some other questions, if I put my image inside of a Canvas that will cause the entire image to be rendered, and when moved it will be rendered correctly. The problem is that I don't want my image to be in a Canvas, since that prevents any other layout from occurring - the HorizontalAlignment and VerticalAlignment properties are ignored (so the image is no longer centered), and I need to implement an option that will draw the image as large as possible to fill the entire area of the window which no longer works (setting the Stretch property to UniformToFill doesn't do anything).
Currently the two transforms are set to the RenderTransform property. If I use LayoutTransform instead, the entire image is drawn, but this also prevents the user from moving any portion of the image off the edge of the window (which is behavior that I would like to keep).
How can I tell WPF to always render the entire image without using a Canvas or a LayoutTransform?

I suggest not using a TranslateTransform but instead rely on the ScrollViewer.
<ScrollViewer>
<Grid>
<Image Source="blabla">
<Image.LayoutTransform>
<ScaleTransform />
</Image.LayoutTransform>
</Image>
</Grid>
</ScrollViewer>
The ScrollViewer gives the Image infinite space to expand, the entire image will be rendered. The Grid forces a centered layout while still allowing the image to expand. If you don't like the scrollbars to control the translate then you can hide them and roll your own solution.
LayoutTransform is definetely the way to go, so that the image's actual size in pixels (based on the zoom) is properly reflected onto your window.

Related

[XAML-WP8.1]Grid View background image clip to bounds

I'm new on Windows development and more in Windows Phone Development.
I'm trying to create a grid view composed of three cell.
Each grid view are composed of one image (for the background) and a textblock.
My background image is a cloud image and I want the first image partialy hidden by the second one and the second one partially hidden by the third one.
I tried to play with the margin of the cell for the y part, that's works but my cloud image doesn't make the entire width of my cell. So I tried the "UnifirmToFill" option but my images are cropped...
On iOS development in this case we can use the magic property "ClipToBounds", everywhere I saw the answer "use the clip to bounds property" but apparently this property is a legend or Visual Studio lie me...
Do you have an idea to resolve my problem ?
Thank you in advance!
To resume:
If I use the "uniformToFill" stretch option, my image is zoomed. It is ok for me.
But there is a way to display the cropped part? I want my image zoomed and displayed out the cell view.
In XAML there are four possible Stretch options:
None
The image is shown in it's original size. If its larger than the parent element, it'll only show the top left portion of the image that fits inside. If the image is smaller than the parent element, then it's shown in it's entirety.
Fill
The image is resized to fill the parent element. If the aspect ratios are different, then the image will be stretched to fit the parent. This will distort the image.
Uniform
The image will be scaled up as large as it can be, while still being completely inside of the parent. Unlike Fill which will stretch the image to make it fit perfectly, Uniform will keep the aspect ratio of the image and stop scaling when it reaches the bounds of the parent.
UniformToFill
This is the bastard child of the previous two. It will scale the image, while keeping the aspect ratio, until it fills the parent element. This means that some parts of the image will be clipped if the aspect ratios are different.
For more information on the Stretch enumeration, hit it up on MSDN
UPDATE
If you want to show the image outside of the bounds of the parent you could do something like this:
<Grid Width="100" Height="50">
<Grid.Clip>
<RectangleGeometry Rect="0 0 100 50"/>
</Grid.Clip>
</Grid>
This was suggested here on SO

Panning contents of a Canvas in a ScrollViewer

I'm trying to implement panning within a Canvas within a scrollviewer like:
<ScrollViewer>
<Canvas>
<!-- some visual elements here -->
</Canvas>
</ScrollViewer>
I want a click and drag operation within the canvas to cause the contents of the canvas to move. I've tried handling the MouseDown, MouseMove, and MouseUp events to do a translation in the manner described here but it hasn't worked.
Any ideas?
You can't do that with your current setup. A Canvas will stretch beyond its parent container and the scrollviewer won't know the size of the Canvas (it will tell it it doesn't need to scroll) and therefore can't create the handles.
If you want to skip with that set up change the canvas to a grid and use the Vertical Scroll and Horizontal Scroll and associated set properties to move the visible section of the grid around.
Try giving your Canvas a set Width and Height and give it a background color (Transparent should be fine) and see if that helps you get your mouse events.

Getting position of rendered image inside Image control

I have an Image control with Stretch==Uniform which means larger images will be scaled down. In my case the Image control fills the whole client space, the scaled down image is being displayed centered inside the control. What now will happen: the size of the rendered image and the Image control do not have the same size - the Image control is usually larger than its content (since I use uniform stretching).
I now need to know the position of the actual image inside the Image control. Some background: the user can place a rectangle on the image to crop it. To match the rectangle with the image coordinates I need to know exactly where the image is.
Is there a way to determine the position of the rendered image inside the Image control? Or is the only solution to make the control the same size as the image content?
To get more control, you might want to put the image on a canvas inside a viewbox.
That way you get pixel control via the canvas, but a scaled view via the outer viewbox. Set the canvas dimensions to match the image and add any decorations to the canvas.
You may need to inverse-scale the rectangle stroke width so that it is visible when the canvas is small.

How to create a UserControl with an irregular shape?

In my Silverlight 4 application I need to create a user control with an irregular shape. The "main display" of the UC is a standard rectangle but I need to have tabs (simple text blocks, where the user can click) that are outside of the main display rectangle.
Is this possible with Silverlight 4? If so, how?
Thanks in advance.
You can position elements of a control outside its normal layout in a number of ways. You could use Canvas but if most of the control is standard Grid rectangle then you can use a Grid. The trick is to use negative Margins.
<Grid x:Name="LayoutRoot">
<Border Margin="0 -22 0 0">
<TextBlock Text="I appear above the UserControl layout" />
</Border>
</Grid>
Note that if the Usercontrol is being used as the Visual root then this won't work because the Silverlight plugin will not render beyound its client rectangle.
It is, you can have transparent background behind the tabs which can let clicks through, effectively behaving as if the shape was different. The UserControl will still have a rectangular shape including the tabs, unless you wrap then into a Popup and float out of the UC with some offset.
Technically, you can have elements outside the UserControl's rectangle if you use a Canvas for your LayoutRoot instead of a Grid. Elements in a Canvas aren't clipped to the canvas size. I wouldn't recommend this, however, because you won't be able to use Margin to size and align your controls inside it. It would be better to have all child controls inside a Grid LayoutRoot.
Which brings us to the question of irregularity. If you want to 'see through' parts of the control and be able to click through them (i.e. click objects underneath it), all you need to do is keep the UserControl's and the LayoutRoot's Background to null or just not set it at all. Wherever there is a lack of any background, clicks will go through. Note that if you set the background to Transparent it will make the control behave as a rectangle (as if it's filled with solid color) with respect to mouse input.
Another thing is if you want to see HTML controls under the see-through parts of your app. Then, you'll have to use windowless mode, but that's another can of worms.

WPF Resizable Canvas

I need to implement a Canvas which scales its contents according to its size. I know there is Viewbox, which scales everything inside of it. However I cannot use that, because some elements have a fixed size and cannot be scaled.
Also how can I bind the size of the Canvas to the parent element (for example a resizable window). There is sizeToContent for windows, I want the size fitting exactly the other way round. Also the canvas uses some drawing based on the size of the hosting element, how is redraw triggered and how can I ensure that it only draws if it gets a valid (or min) size?
If you don't specify any width or height to the canvas it automatically uses all the available space. This is because the default VerticalAlignment and HorizontalAlignment are set to Stretch.
What do you mean by canvas that scales it's contents according to it's size without scaling all the contents as some have fixed size?
Update after comments
If your drawing algorithm already scales the content to the canvas' height and width then all you need to do is to resize the canvas to fit the area I believe? In that case just remove the hardcoded height/width values and the canvas will resize to fit the container.
You might need to use ActualHeight/ActualWidth instead of Height/Width in the drawing algorithm after this though. ActualHeight/ActualWidth return the values that the layout container will give your canvas so these represents the values the canvas is drawn with.
I think you can find the answers to all your questions in my London Underground demo.
I'm doing this from memory, but if I recall correctly a Window uses either a Panel or a Canvas as part of it's ControlTemplate (in which lies the ContentPresenter), which means that a Canvas placed directly in a Window will have issues resizing automatically like it might elsewhere. There are a few basic ways to address this.
1 Write a new ControlTemplate for your Window to use. :(2 Place your content directly in the Window rather than in a Canvas inside the Window. :/
3 Do a by-name binding. :)
<MyWindow x:Name="topWindow">
<Canvas x:Name="topCanvas" Width="{Binding ElementName=topWindow, Path=ActualWidth}" Height="{Binding ElementName=topWindow, Path=ActualHeight}">
...Content...
</Canvas>
</MyWindow>
(As it happens, I often bind grids inside Canvases in this fashion, so I can easily animate items moving from one grid position to another.)

Resources