How to prevent the Visual Brush from stretching its content - wpf

In my project I want to display a small logo on the side of a custom control. Since I have no canvas I thought maybe a Visual Brush would be a good Idea to place the logo in the background.
<VisualBrush>
<VisualBrush.Visual>
<Rectangle Width="200" Height="200" Fill="Red" />
</VisualBrush.Visual>
</VisualBrush>
But the Rectangle I am using right now is not 200x200. It takes the complete available space. Thats not what I want. I also tried a Viewbox and set the stretch property but the result is the same because in the end I don't need a simple Rectangle but a canvas with many path objects as children. A Viewbox supports only one child.
This there any way to get around this problem?

You need to set TileMode, Stretch, AlignmentX and AlignmentY properties on your VisualBrush:
<VisualBrush TileMode="None" Stretch="None" AlignmentX="Left" AlignmentY="Top">
<VisualBrush.Visual>
<Rectangle Height="200" Width="200" Fill="Red"></Rectangle>
</VisualBrush.Visual>
</VisualBrush>

Add Grid and this Set Vertical alligment to Top and Horizontal alignment to Right
Sample code
<VisualBrush x:Key="myVisual">
<VisualBrush.Visual>
<Grid>
<Rectangle Height="200" Width="200" Fill="Red" HorizontalAlignment="Right" VerticalAlignment="Top" ></Rectangle>
</Grid>
</VisualBrush.Visual>
</VisualBrush>

For me, I set the following attribute on the VisualBrush, and the VisualBrush now looks exactly like a MediaElement:
Stretch="Uniform"

Related

Canvas is clipped when size is too big

I am using a canvas with the an ImageBrush to dispaly an image. I am setting the size of the canvas to the original size of the image so I can get the coordinates when I move the mouse etc.
The problem is that when I put the canvas in a control (Grid for example) with a smaller size the Canvas is clipped.
<Grid>
<Canvas Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Canvas.Background>
<ImageBrush ImageSource="{Binding Image, Converter={StaticResource imgConverter}}"/>
</Canvas.Background>
</Canvas>
</Grid>
Is there a way to keep the canvas size without being clipped?
I've been meaning to dig deeper in to the source to work out where the clipping occurs for a while now, but never get around to doing it. I've been using a not-so-nice trick of inserting a Canvas into the visual tree when this happens as a workaround.
There are a number of controls that clip the child visuals; Grid, StackPanel, etc. As I mentioned the usual quick fix is to use a Canvas after the container that causes the clip.
In your snippet are there more containers higher up the visual tree?
If the depth was actually something like this:-
<StackPanel>
<Grid>
<Canvas Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Canvas.Background>
<ImageBrush ImageSource="{Binding Image, Converter={StaticResource imgConverter}}"/>
</Canvas.Background>
</Canvas>
</Grid>
</StackPanel>
Then this might cause clipping. If you insert another Canvas further up the visual tree then this clipping is removed.
<StackPanel>
<Canvas>
<Grid>
<Canvas Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" >
<Canvas.Background>
<ImageBrush ImageSource="{Binding Image, Converter={StaticResource imgConverter}}"/>
</Canvas.Background>
</Canvas>
</Grid>
</Canvas>
</StackPanel>
This workaround can then become problematic if it alters other layout needs for other controls.

WPF / Xaml, vertical aligment of LineGeomtry inside grid not working properly

I try to get into creation of custom controls with for WPF. I found many good
tutorials and advises on the web so I started width a really simple example to get
my hands dirty and get some practice. I figured out that the issue stumbled across
is not really related to the subject of custom controls. So I extracted the xaml code to a simple wpf form.
<Window x:Class="WpfVerticalAigmentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="200">
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20" VerticalAlignment="Center" >
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="100,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
</Grid>
My expectation was to get a line centered in the grid and claiming the half of the stroke thickness on each side from the center. But as the linked image shows differs from my expectation.
"Resulting visualization"
So it look like I missed a detail about the line shape or linegeomtry. How do I get the the line displayed as shown in the following image?
"Expected result"
You need to match the Width and Height of the LineGeometry to the Width and Height of the Path and set the VerticalAlignment property to Bottom:
<Grid Height="20" Width="200" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red" StrokeThickness="20" VerticalAlignment="Bottom">
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="200,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
If your goal is your the expectaions, and not the way how u have reached this, I could prefer to you this:
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Border BorderThickness="10" VerticalAlignment="Center" BorderBrush="Red" />
</Grid>
</Grid>
The problem here is that the starting point of the XY Coordinates of the Path starts on the top left, and the stroke expands in both directions but thereby only makes the Path bigger to the bottom (I can't really tell you why, but that's just what seems to happen).
You can see this pretty good in the Design View:
To work around this simply move your Y Coordinates down half of the stroke size.
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Path VerticalAlignment="Center"
Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Grid>
Or wrap it in another control (Canvas is the commonly used controls for Paths) with the desired height:
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Canvas Height="20" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Canvas>
</Grid>
And you are good to go:

Scale a Visual Brush Background WPF

I have a Item called MiniMap in my xaml. I have set the background of it to a visual brush representting a canvas Item. Now, I want to scale the background to a ratio 0.7 . How can I do it?
Thanks in advance
<local:MiniMap Width="201" Height="134" x:Name="MiniMapItem" MinHeight="100" MinWidth="100" Opacity="1" SnapsToDevicePixels="True" Margin="0,0,20,20" VerticalAlignment="Bottom" HorizontalAlignment="Right">
<local:MiniMap.Background>
<VisualBrush Visual="{Binding ElementName=viewport}" Stretch="None" TileMode="None" AlignmentX="Left" AlignmentY="Top" />
</local:MiniMap.Background>
</local:MiniMap>
Try this:
<VisualBrush Visual="{Binding ElementName=viewport}" Stretch="None" TileMode="None" AlignmentX="Left" AlignmentY="Top">
<VisualBrush.Transform>
<ScaleTransform ScaleX="0.7" ScaleY="0.7" />
</VisualBrush.Transform>
</VisualBrush>
You may need to play with the CenterX and CenterY properties to get it to look right. Usually you'll want them to be set to the middle point of what you're scaling.
The VisualBrush element has the property Viewbox, which can be used to scale the background.

Use UIElement as Clip in WPF

Please pardon my ignorance- I'm very new to WPF.
I am looking to implement a minor, visual effect in my application that gives the look of "inner" rounded corners. The window in question has a dark border that encapsulates several UIElements, one of which is a StatusBar, located at the bottom of the window. This StatusBar has a dark background that matches the window's border. Above the StatusBar is a content view, which is currently a Grid- its background is semi-transparent (I think that this is something of a constraint- you can see through the content view to the desktop below). I would like for the content view (represented by the transparent, inner area in the figure below) to have the look of rounded corners, though I expect to have to sort of create the illusion myself.
(Can't post the image because I'm a lurker and not a poster- please find the drawing here)
My first approach was to add a Rectangle (filled with the same, dark color as the border) immediately above the StatusBar and to assign a Border with rounded corners to its OpacityMask (similar to the solution proposed by Chris Cavanagh**). Sadly, the effect that is produced is the exact opposite of that which I am trying to achieve.
I understand that the Clip property can be of use in this sort of situation, but it seems to me that using any sort of Geometry will prove to be inadequate as it won't be dynamically sized to the region in which it resides.
EDIT: Including my XAML:
<Grid Background="{StaticResource ClientBg}" Tag="{Binding OverlayVisible}" Style="{StaticResource mainGridStyle}">
<DockPanel LastChildFill="True">
<!-- Translates to a StackPanel with a Menu and a Button -->
<local:FileMenuView DockPanel.Dock="Top" />
<!-- Translates to a StatusBar -->
<local:StatusView DockPanel.Dock="Bottom" />
<!-- Translates to a Grid -->
<local:ContentView />
</DockPanel>
</Grid>
Any pointers are more than welcome- I'm ready to provide more indepth detail if necessary.
** http://www.dotnetkicks.com/wpf/WPF_easy_rounded_corners_for_anything
EDIT: Now I got what you mean. In fact you can use Path + OpacityMask approach. You have to draw "inverted" path, to use it as opacity mask. But I have simpler and faster solution for you :). Use Border + CornerRadius, and fill the gaps with solid paths. Just try the following code in Kaxaml and let me know if this is what you were looking for:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="240"
Height="320"
AllowsTransparency="True"
Background="Transparent"
WindowStyle="None">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Border Background="Black"/>
<Border Grid.Row="1" BorderBrush="Black" BorderThickness="5">
<Grid>
<Border Background="White" CornerRadius="0, 0, 5, 5" Opacity="0.7"/>
<Path
Width="15"
Height="15"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Data="M10,10 L5,10 L5,5 C4.999,8.343 6.656,10 10,10 z"
Fill="Black"
Stretch="Fill"/>
<Path
Width="15"
Height="15"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Data="M10,10 L5,10 L5,5 C4.999,8.343 6.656,10 10,10 z"
Fill="Black"
Stretch="Fill">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
<TranslateTransform X="15"/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Border>
<Border Grid.Row="2" Background="Black"/>
</Grid>
</Window>
PS: You can simplify this solution by avoiding render transforms, but you got the idea.

How can you align a canvas background in WPF?

I have set a canvas' background to an image of a company logo. I would like for this image to be aligned to the bottom right corner of the canvas.
Is it possible to do this, or would it require for the image to be added into the canvas as a child? That would not work with this program as all children of the canvas are handled differently.
Thank You
Will this work? (It worked for me, anyway.)
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="someimage.jpg" AlignmentX="Right"
AlignmentY="Bottom" Stretch="None" />
</Canvas.Background>
</Canvas>
AFAIK The WPF Canvas needs child UI elements to be positioned using absolute co-ordinates.
To achieve the right-bottom-anchored effect, I think you'd need to handle the window resize event, recalculate and apply the Top,Left co-ordinates for the child Image element to always stick to the right buttom corner.
<Window x:Class="HelloWPF.Window1" xmlns...
Title="Window1" Height="300" Width="339">
<Canvas>
<Image Canvas.Left="195" Canvas.Top="175" Height="87" Name="image1" Stretch="Fill" Width="122" Source="dilbert2666700071126ni1.gif"/>
</Canvas>
</Window>
How about containing the canvas and image inside of a Grid control like so?
<Window ...>
<Grid>
<Canvas/>
<Image HorizontalAlignment="Right" VerticalAlignment="Bottom" .../>
<Grid>
</Window>
This is my solution using a border inside the canvas to align the image. This solution works well when canvas is resized:
<Canvas x:Name="MiCanvas" Height="250" Width="500" Background="Aqua">
<Border x:Name="MiBorderImage"
Width="{Binding ElementName=MiCanvas, Path=ActualWidth}"
Height="{Binding ElementName=MiCanvas, Path=ActualHeight}"
Background="Transparent">
<Image x:Name="MiImage" Source="/GraphicsLibrary/Logos/MiLogo.png"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Stretch="None" />
</Border>
</Canvas>

Resources