This question already has answers here:
WPF Clipping Problem
(2 answers)
Closed 5 years ago.
I try to rotate an image in a ScrollViewer (WPF), but the entire image needs to remain visible. The corners of the image are cut off, if rotation angle is for example 45. I tried setting the Width and Height of the image by calculation the surrounding rectangle of the rotated image. It works, but not if the rotation angle is over 45.
<Grid>
<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Visible" Margin="0,0,0,0">
<Image x:Name="image" RenderTransformOrigin="0.5,0.5" Margin="0,0,0,0" MouseDown="image_MouseDown" MouseRightButtonDown="image_MouseRightButtonDown" MouseLeftButtonDown="image_MouseLeftButtonDown">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="scal"/>
<SkewTransform/>
<RotateTransform Angle="90" x:Name="rot"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</ScrollViewer>
</Grid>
Use a ViewBox in the following structure:
<ScrollViewer Width="100" Height="100" Background="Black" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Viewbox Width="100" Height="100">
<Border Width="100" Height="100" Background="Red" >
<Border.LayoutTransform>
<RotateTransform Angle="30" />
</Border.LayoutTransform>
</Border>
</Viewbox>
</ScrollViewer>
Note that you should set the size of the ViewBox and the inner Control (in your case the Image) equal to the size of the ScrollViewer. The ViewBox will adjust the size of the inner Control, in such a way that the ScrollBars are never Visible.
Note that I used a red Border, you can add the image.
Edit
Just checked it. You do not need to set the Widths, but just the size of inner Control. In other words, this works too:
<ScrollViewer Background="Black" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Viewbox>
<Border Width="1" Height="1" Background="Red" >
<Border.LayoutTransform>
<RotateTransform Angle="30" />
</Border.LayoutTransform>
</Border>
</Viewbox>
</ScrollViewer>
Related
I want to make a set of buttons with 90 degree rotated text. I created the layout I wanted but found when I attached it to a button the layout clipped according to the button's (unrotated) layout. I haven't been able to figure out what's going on, but I created a simplified case without a button. Here's my XAML:
<Border Height="100" Width="50" BorderThickness="1" BorderBrush="Black">
<TextBlock>This is a test</TextBlock>
</Border>
This produces a border with clipped text (as expected)
But if I rotate the text, resulting in this XAML:
<Border Height="100" Width="50" BorderThickness="1" BorderBrush="Black">
<TextBlock RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="90"/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>This is a test</TextBlock>
</Border>
the text still clips according to the ''width'' of the enclosing border, not the height.
I'm sure I could size the border to include the text and rotate the border instead, and likely I could do the same with the buttons I'm trying to create, but if I do I don't know that I'm not going to run into the same problem with whatever bounds the buttons, so I feel like I need to understand what I'm missing. Why would a rotated object be clipped as if it wasn't rotated?
Set the LayoutTransform property, instead of RenderTransform:
<Border Height="100" Width="50" BorderThickness="1" BorderBrush="Black">
<TextBlock Text="This is a test">
<TextBlock.LayoutTransform>
<RotateTransform Angle="90"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Border>
If desired, also set HorizontalAlignment="Center" and VerticalAlignment="Center" on the TextBlock.
When I place the following code in a Window or UserControl, the image is displayed with its native width and height. Is there a way to automatically scale outer canvas to proportions of the containing window while retaining the proper aspect ratio for the window?
<Canvas Background="AliceBlue">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</Canvas.LayoutTransform>
<Image Source="ImageName.jpg" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Canvas Canvas.Top="20" Canvas.Left="20" Width="20" Height="20" Background="Salmon"/>
</Canvas>
A Canvas never resizes its child elements. Put the Image control in a Grid instead, then probably put the whole thing in a Viewbox:
<Viewbox>
<Grid>
<Image Stretch="None" Source="ImageName.jpg" .../>
<Canvas Margin="20,20,0,0" Width="20" Height="20" Background="Salmon"/>
</Grid>
</Viewbox>
Wrap your Canvas in a ViewBox.
When i draw items in canvas, the position is take from top of the item inside canvas:
<Canvas Name="cnvMain"
Width="80"
Height="80">
<Ellipse Canvas.Top="20"
Canvas.Left="40"
Width="40"
Height="40"
Fill="Gray" />
</Canvas>
Now what i would need is to take the measurement from the bottom of the element, like this:
In the end i would like to be able to set the distance from the bottom of the Ellipse to the top of the Canvas.
NB: Ellipse can sometimes not be a circle and flipping it upside down is not an option. Also i dont know the height before runtime so setting negative margin in xaml will not work also.
(Picture and example xaml taken from: http://weblogs.asp.net/psheriff/centering-text-within-a-wpf-shape-using-a-canvas)
If you want to specify the distance of the bottom of the Ellipse to the bottom of the Canvas, you could replace Canvas.Top by Canvas.Bottom:
<Ellipse Canvas.Bottom="20" Canvas.Left="40" Width="40" Height="40" Fill="Gray"/>
For the distance from the bottom of the Ellipse to the top of the Canvas, you may specify a negative Margin:
<Ellipse Canvas.Top="20" Canvas.Left="40" Width="40" Height="40" Fill="Gray"
Margin="0,-40,0,0"/>
or an appropriate RenderTransform:
<Ellipse Canvas.Top="20" Canvas.Left="40" Width="40" Height="40" Fill="Gray">
<Ellipse.RenderTransform>
<ScaleTransform ScaleY="-1"/>
</Ellipse.RenderTransform>
</Ellipse>
In order to invert the y direction of the whole Canvas coordinate system, you may apply a RenderTransform to the Canvas:
<Canvas ... RenderTransformOrigin="0,0.5">
<Canvas.RenderTransform>
<ScaleTransform ScaleY="-1"/>
</Canvas.RenderTransform>
...
</Canvas>
Edit: You may also put the Ellipse in another Canvas with zero Height, and attach it to the lower Canvas border:
<Canvas Canvas.Top="20" Canvas.Left="40" Width="0" Height="0">
<Ellipse Canvas.Bottom="0" Width="40" Height="40" Fill="Gray"/>
</Canvas>
<ScrollViewer x:Name="imagescrollviewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<!--<Viewbox>-->
<Image x:Name="im" Source="{Binding JpgImageSource}" RenderTransformOrigin="0.5,0.5" Stretch="Uniform">
<Image.RenderTransform>
<ScaleTransform ScaleX="{Binding Value,ElementName=scaleslider}" ScaleY="{Binding Value,ElementName=scaleslider}"/>
</Image.RenderTransform>
</Image>
<!--</Viewbox>-->
</ScrollViewer>
<Slider x:Name="scaleslider" Orientation="Vertical" Height="100" Margin="5" HorizontalAlignment="Center" Maximum="4" Minimum="0.2" Value="1"/>
The scrollbar doesn't adpat to the image size properly. When the image gets bigger, the scrollbar should be shorter and vice versa. Is there some way to figure out the problem?
How to know the slider value when the image is fit to the window?
I suppose you need to use LayoutTransform instead of RenderTransform. This blog post describes the difference very well.
<Image x:Name="im" Source="{Binding JpgImageSource}" >
<Image.LayoutTransform>
<ScaleTransform ScaleX="{Binding Value,ElementName=scaleslider}" ScaleY="{Binding Value,ElementName=scaleslider}"/>
</Image.LayoutTransform>
</Image>
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black">
<!-- Rounded yellow border -->
<Border BorderThickness="3" BorderBrush="Yellow" CornerRadius="10" Padding="2"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<!-- Rounded mask (stretches to fill Grid) -->
<Border Name="mask" Background="White" CornerRadius="7"/>
<!-- Main content container -->
<StackPanel>
<!-- Use a VisualBrush of 'mask' as the opacity mask -->
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=mask}"/>
</StackPanel.OpacityMask>
<!-- Any content -->
<Image Source="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg"/>
<Rectangle Height="50" Fill="Red"/>
<Rectangle Height="50" Fill="White"/>
<Rectangle Height="50" Fill="Blue"/>
</StackPanel>
</Grid>
</Border>
</Page>
This XAML is from WPF – Easy rounded corners for anything but it doesn't work form me =(
<Border Canvas.Left="55"
Canvas.Top="30"
Width="100"
Height="Auto"
Margin="12,12,8,0"
VerticalAlignment="Top"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="18">
<Border.Effect>
<DropShadowEffect BlurRadius="5"
Opacity=".5"
ShadowDepth="3" />
</Border.Effect>
<Border Name="ReceiverColor"
BorderBrush="#FF96B2E4"
BorderThickness="6"
CornerRadius="15">
<Border Name="Mask"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="13">
<StackPanel>
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Mask}" />
</StackPanel.OpacityMask>
<Image Name="Receiver" />
</StackPanel>
</Border>
</Border>
</Border>
--- EDIT ---
I make borders sizes to auto and change source of image to an image from a link
when window loaded border size becomes as image size but image not shown !!!
You can define a <Border/> element and set its <Border.Background/>
property to an <ImageBrush/> , set the Borders CornerRadius property and you
are all set!
<Border CornerRadius="8,0,8,0">
<Border.Background>
<ImageBrush Stretch="Fill" ImageSource="ImageSource"/>
</Border.Background>
</Border>
You forgot the Grid that makes the mask and the image siblings and nested the image in the mask. and you forgot to set the background of the mask.
This works:
<Grid>
<Border Canvas.Left="55"
Canvas.Top="30"
Width="100"
Height="Auto"
Margin="12,12,8,0"
VerticalAlignment="Top"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="18">
<Border.Effect>
<DropShadowEffect BlurRadius="5"
Opacity=".5"
ShadowDepth="3" />
</Border.Effect>
<Border Name="ReceiverColor"
BorderBrush="#FF96B2E4"
BorderThickness="6"
CornerRadius="15">
<Grid>
<Border Name="Mask"
Background="White"
BorderBrush="#FF3B5998"
BorderThickness=".5"
CornerRadius="13">
</Border>
<StackPanel>
<Image Name="Receiver"
Source="/Images/test.jpg" />
<StackPanel.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Mask}" />
</StackPanel.OpacityMask>
</StackPanel>
</Grid>
</Border>
</Border>
</Grid>
in wpf this one works for me
<Ellipse Width="50" Height="50">
<Ellipse.Fill>
<ImageBrush ImageSource="http://chriscavanagh.files.wordpress.com/2006/12/chriss-blog-banner.jpg" />
</Ellipse.Fill>
</Ellipse>
None of the above answers worked for me completely. I was trying to implement rounded corners on image which could be resized and has properties Stretch="UniformToFill" VerticalAlignment="Center" and HorizontalAlignment="Center".
The center alignments keeps the middle part cropped as opposed to bottom and right side being cropped, when image is resized. Solutions with image brush were working but I was facing problem in keeping the content at center cropped.
The marked answer has a problem with transparent non rectangular images as the "mask" border will end up showing as white background. Following was the imlementation which worked for me:
<Grid>
<WrapPanel Name ="container">
<Image Source="sample_image.png" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="UniformToFill"/>
<WrapPanel.OpacityMask>
<VisualBrush >
<VisualBrush.Visual>
<Border Height="{Binding ElementName=container, Path=ActualHeight}"
Width="{Binding ElementName=container, Path=ActualWidth}"
Background="White" CornerRadius="15" />
</VisualBrush.Visual>
</VisualBrush>
</WrapPanel.OpacityMask>
</WrapPanel>
</Grid>
You can use an ellipse like how Usman Ali has said (I thought this myself and I didn't take it from him)
It's very simple, make an ellipse with the properties you want, then set the fill to an imagebrush with your desired image like this in XAML:
<Ellipse Height="Auto" Width="100">
<Ellipse.Fill>
<ImageBrush ImageSource="YOUR IMAGE SOURCE/LINK HERE"/>
</Ellipse.Fill>
</Ellipse>
In C#, if in any case you want to do in C#:
Ellipse YourEllipseName = new Ellipse
{
Height = 50,
Width = 50,
StrokeThickness = 0,
Fill = new ImageBrush
{
Stretch = Stretch.Uniform,
ImageSource = new BitmapImage(new Uri("YOUR IMAGE SOURCE HERE"))
}
};
<Grid Background="Black">
<Rectangle RadiusX="20" RadiusY="20"
Width="130"
Height="130">
<Rectangle.Fill>
<ImageBrush x:Name="myImage" ImageSource="C:\Path\Desktop\visual-studio-2010-logo.png"/>
</Rectangle.Fill>
</Rectangle>
</Grid>