Background drawing with inner offset - wpf

I want my UserControl to have black background. The little thing is that I want it to have some offset from the sides.
I did it like this:
<UserControl x:Class="PitramVisionPlayerUI.Controls.Readout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="200">
<UserControl.Background>
<DrawingBrush Stretch="Fill">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="0.1,0.1">
<PathFigure.Segments>
<LineSegment Point="0.9,0.1" />
<LineSegment Point="0.9,0.9" />
<LineSegment Point="0.1,0.9" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Black"></SolidColorBrush>
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</UserControl.Background>
</UserControl>
Problem is that it does not work. It keeps filling the whole rectangle. If I replace DrawingBrush's property Stretch from "Fill" to "None" I am getting a black dot right in the middle of my UserControl.

Without a precise description of how exactly you want your control to behave, it's impossible to provide precise details as to exactly what your code should look like.
As a general rule, for a DrawingBrush (or any TileBrush for that matter), you can use the Viewbox and Viewport properties to modify how the basic content of the brush is rendered. For example, by providing a viewbox that is a little larger than the actual content, it is possible to shrink the overall rendering within the viewport (i.e. the output area).
But, it's been my experience that the viewbox/viewport approach is always a bit "fiddly". Or rather, it's hard to gain a good intuitive grasp of what those parameters do, and so one often winds up just fiddling with the values until they get the results they want, with the result that the implementation is not very well generalized or reusable.
From your question, it's unclear what your desired relationship between this inset black background and the rest of the content in the control would be. However, one very straightforward approach would be simply to set the Padding property of the UserControl itself, thus causing all of the content inside the control to be inset by the given padding amount.
For example:
<UserControl x:Class="TestSO58234176BackgroundBorder.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:l="clr-namespace:TestSO58234176BackgroundBorder"
<!-- Padding set to 5 pixels, so content (including background) is inset -->
Padding="5" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="Black">
<!-- Stretch the text so it's clear what the extent of the content is -->
<Viewbox Stretch="Fill">
<TextBlock Text="This is a test" Foreground="LightGreen" FontWeight="Bold"/>
</Viewbox>
</Grid>
</UserControl>
This will do exactly that. I.e. all of the content, including any background it has, will be inset within the user control by 5 pixels. It looks like this:
(The red border is in the window's markup, around the user control, so it's easier to see the actual dimension of the user control itself.)
On the other hand, maybe you want for the content to fill the control completely, but have just the background inset. While (as I mentioned) you can fiddle with the background brush's viewbox and viewport for complete control of the rendering of the background, and in theory this might even be the "best" or "most correct" way to do it, in most cases it should not be necessary. Instead, just provide separate element providing the background and which is displayed under the rest of the content of the control.
<UserControl x:Class="TestSO58234176BackgroundBorder.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:l="clr-namespace:TestSO58234176BackgroundBorder"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<!-- Put a black rectangle under the actual content of the control, to act as an inset background -->
<Rectangle Fill="Black" Margin="5"/>
<!-- Put the actual content of the control inside this <ContentControl/> element -->
<ContentControl>
<Viewbox Stretch="Fill">
<TextBlock Text="This is a test" Foreground="LightGreen" FontWeight="Bold"/>
</Viewbox>
</ContentControl>
</Grid>
</UserControl>
That would look like this:
While the above example uses a <ContentControl/> element to contain the actual content of the user control, this isn't strictly necessary. It's just a convenient way to represent "here's where all your content goes". But of course, any sort of content can go here, as long as it's a valid child of a <Grid/>. The key here is that it shares the grid cell with the inset <Rectangle/> element that is acting as the background, and so renders as overlaid on top of that background.
If you like, you can even generalize the above, so that the "background" rectangle is part of the user control's template, instead of direct content. This way, there's a clear separation between what's part of the user control's visual aspect itself, and what's the actual content of the user control:
<UserControl x:Class="TestSO58234176BackgroundBorder.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:l="clr-namespace:TestSO58234176BackgroundBorder"
mc:Ignorable="d"
Padding="5"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Template>
<ControlTemplate TargetType="{x:Type l:UserControl1}">
<Grid>
<Rectangle Fill="Black" Margin="5"/>
<ContentPresenter/>
</Grid>
</ControlTemplate>
</UserControl.Template>
<Viewbox Stretch="Fill">
<TextBlock Text="This is a test" Foreground="LightGreen" FontWeight="Bold"/>
</Viewbox>
</UserControl>

Related

WPF StackPanel - how to push items off bottom

I have a StackPanel spanning the entire screen vertically in a grid, and the panel's VerticalAlignment option set to Bottom. When I add items to the panel in code, their positions start at the bottom, and move up when I add more. This is desired. However, what is not desired is that after the screen is filled vertically with items, adding more pushes them off the top of the screen. My desire is to have additional items fall off the bottom; I don't care if they are not visible; I just don't want the topmost items to disappear.
Any tricks you might know of to help me through this? Thank you in advance.
My desire is to have additional items fall off the bottom
You need to wrap the StackPanel in another container that allows the StackPanel itself to grow as much as it wants, in a way that makes the StackPanel appear to expand from the bottom, but in reality expand from the top so that when it exceeds available space, the excess is removed from the bottom instead of the top.
The Grid control will do exactly that. For example:
<Window x:Class="TestSO67169225StackPanelFromBottom.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="36"/>
</Style>
</Window.Resources>
<Grid VerticalAlignment="Bottom">
<StackPanel>
<TextBlock Text="StackPanel Item 1"/>
<TextBlock Text="StackPanel Item 2"/>
<TextBlock Text="StackPanel Item 3"/>
<TextBlock Text="StackPanel Item 4"/>
<TextBlock Text="StackPanel Item 5"/>
<TextBlock Text="StackPanel Item 6"/>
</StackPanel>
</Grid>
</Window>
Looks like this:
But when you add more items, looks like this:

WPF UserControl as Polygon

I am very new at this WPF world, i have some experience in the classic Windows Desktop applications.
I am trying to create a custom UserControl polygon shaped.
I have tryied creating a Path Data and then setting the UserControl Opacity property to "0", but it makes transparent the whole UserControl.
For example, i have build this Polygon inside the user control
<UserControl x:Class="WindowsFormsApp2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Opacity="100">
<Grid x:Name="LayoutRoot">
<Path Data="M-70.616296,46.859802 L7.3270039,-1.2587545 174.31959,52.958763 168.71134,98.185567 z" Fill="#FF2121D6" HorizontalAlignment="Left" Height="100" Margin="138,114,0,0" Stretch="Fill" Stroke="Black" Opacity ="100" VerticalAlignment="Top" Width="246"/>
</Grid>
As you can see the user control is 640x480 so when i add code to the UserControl_MouseLeftButtonDown event, it fires if clicking in ay position inside the 640x480 while i want only to fire when clicking inside the polygon.
I have been googling for a solution but i can't found any solution, ¿maybe what i want it's not possible?
You may template a UserControl to look like a polygon:
<UserControl x:Class="WpfApp1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Path Data="M-70.616296,46.859802 L7.3270039,-1.2587545 174.31959,52.958763 168.71134,98.185567 z"
Fill="#FF2121D6" HorizontalAlignment="Left" Height="100" Margin="138,114,0,0"
Stretch="Fill" Stroke="Black" Opacity ="100" VerticalAlignment="Top" Width="246"/>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Or you may just get rid of the UserControl and use the Path element directly. It also has a MouseLeftButtonDown event that you can handle.

Border control expands to size of Grid instead of just surrounding an Image control

I wanted a <Border> around my <Image> - sounds simple enough. but I could never get it to appear. I eventually made it "Red" with "BorderThickness=20" - then it was obvious that it was going around the entire "LayoutRoot"! Something like:
<UserControl x:Class="BorderCrossing.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Margin="10" Background="Black">
<Border Canvas.ZIndex="1" Background="White" HorizontalAlignment="Center" Opacity=".5" VerticalAlignment="Top">
<TextBlock x:Name="idTextBlock" FontSize="20" FontWeight="Bold" Foreground="Black" Text="ID Here" />
</Border>
<Border Canvas.ZIndex="1" Background="Blue" BorderThickness="5" BorderBrush="AntiqueWhite">
<Image x:Name="thumbnailImage" Height="100" Width="100" Stretch="Uniform" />
</Border>
</Grid>
In order to "fix" this, I found that adding 'HorizontalAlignment="Left" VerticalAlignment="Top"' to the <Border> placed the border around the <Image>, as desired. I also found that I could enclose the <Border> in a <Canvas> and achieve a similar result.
What is going on? Can someone explain this in a way that will prevent my "wonder" in the future?
Thanks,
David
The default for VerticalAlignment and HorizontalAlignment is "Stretch", so the Border stretches to the entire available space by default. It does not happen inside of a Canvas because a Canvas does not take these properties into account when performing layout of its children, so they get the minimum size based on properties like Width, Height, MinWidth and similar properties of their children. Positioning in a Canvas is done with Canvas.Top and Canvas.Left properties, while a Grid uses the ~Alignment properties as well as Margins.

Set layout to have 100% width and 100% height

How can I set a layout to have 100% width and 100% height?
I want my Silverlight application to stretch in the browser to fill all space.
I am using Expression Blend 4.
Here is my XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="RichardKnopNew.MainPage"
Width="960" Height="540">
<Grid x:Name="LayoutRoot" Width="960" Height="540">
<Grid.Background>
<ImageBrush Stretch="Fill" ImageSource="/bg.jpg"/>
</Grid.Background>
<Rectangle Fill="#FF252525" Stroke="Black" Opacity="0.7" RadiusX="10" RadiusY="10" Margin="25,115,335,25" StrokeThickness="0" Height="400"/>
</Grid>
</UserControl>
Your application should do this automatically. The only reasons why it would not do so are:
You've constrained the size of the Silverlight object in the HTML page that hosts the application, or
You've explicitly set the width/height of the MainPage object in MainPage.xaml.
Setting the Background property of the MainPage object to a non-white colour should demonstrate this. If not, please include more details (including the XAML you are using).
Hope this helps...
Chris

combine image and solidcolor background for a WPF Form

I have a WPF form that I am building. I want to specify a background image for the window, which is easy enough. However, I also want to specify a color so that the area of the form not covered by the image is white. I've seen some examples that show using two different background brushes, but when I try that VS.NET tells me I can't have multiple brushes.
This is the XAML I'm using
<Window x:Class="Consent.Client.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/CompositeWPF"
Title="Shell" WindowStyle="None" WindowState="Maximized" FontSize="24">
<Window.Background>
<ImageBrush AlignmentX="Left" AlignmentY="Top" Stretch="None" TileMode="None" ImageSource="logo_header2.png" />
</Window.Background>
<ItemsControl Background="White" VerticalAlignment="Center" cal:RegionManager.RegionName="MainRegion" >
</ItemsControl>
</Window>
This works great for the image, but the background not covered by the image is black. How do I make it white? Changing the image itself is not really an option.
Try this (I removed everything not directly relevant to the question to make the code clearer):
<Window x:Class="Consent.Client.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="White">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="logo_header2.png" />
</Grid.Background>
<ItemsControl>
</ItemsControl>
</Grid>
</Window>
Basically, set the window's background to the behind the image color, than put a grid in the window and give the grid you background image, put everything inside the grid instead of directly in the window.
As an Extension to Nirs answer. If you want to have margins around your content, but let the background image be able to fill the whole window, you can also stack backgrounds using borders:
<Window x:Class="Consent.Client.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="White">
<Border Padding="10">
<Border.Background>
<ImageBrush ImageSource="logo_header2.png" />
</Border.Background>
<!--<Your content >-->
</Border>
</Window>
I'm not sure you can combine brushes. You could play around with ImageBrush, or you could forget the "background" and stack the items on top of each other in a Grid:
<Window x:Class="Consent.Client.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.codeplex.com/CompositeWPF"
Title="Shell" WindowStyle="None" WindowState="Maximized" FontSize="24">
<Grid>
<Image Source="logo_header2.png" Stretch="None" VerticalAlignment="Top" />
<ItemsControl Background="White" VerticalAlignment="Center" cal:RegionManager.RegionName="MainRegion" >
</ItemsControl>
</Grid>
</Window>

Resources