How to make overlay control above all other controls? - wpf

I need to make a control appear above all other controls, so it will partially overlay them.

If you are using a Canvas or Grid in your layout, give the control to be put on top a higher ZIndex.
From MSDN:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="ZIndex Sample">
<Canvas>
<Rectangle Canvas.ZIndex="3" Width="100" Height="100" Canvas.Top="100" Canvas.Left="100" Fill="blue"/>
<Rectangle Canvas.ZIndex="1" Width="100" Height="100" Canvas.Top="150" Canvas.Left="150" Fill="yellow"/>
<Rectangle Canvas.ZIndex="2" Width="100" Height="100" Canvas.Top="200" Canvas.Left="200" Fill="green"/>
<!-- Reverse the order to illustrate z-index property -->
<Rectangle Canvas.ZIndex="1" Width="100" Height="100" Canvas.Top="300" Canvas.Left="200" Fill="green"/>
<Rectangle Canvas.ZIndex="3" Width="100" Height="100" Canvas.Top="350" Canvas.Left="150" Fill="yellow"/>
<Rectangle Canvas.ZIndex="2" Width="100" Height="100" Canvas.Top="400" Canvas.Left="100" Fill="blue"/>
</Canvas>
</Page>
If you don't specify ZIndex, the children of a panel are rendered in the order they are specified (i.e. last one on top).
If you are looking to do something more complicated, you can look at how ChildWindow is implemented in Silverlight. It overlays a semitransparent background and popup over your entire RootVisual.

Robert Rossney has a good solution. Here's an alternative solution I've used in the past that separates out the "Overlay" from the rest of the content. This solution takes advantage of the attached property Panel.ZIndex to place the "Overlay" on top of everything else. You can either set the Visibility of the "Overlay" in code or use a DataTrigger.
<Grid x:Name="LayoutRoot">
<Grid x:Name="Overlay" Panel.ZIndex="1000" Visibility="Collapsed">
<Grid.Background>
<SolidColorBrush Color="Black" Opacity=".5"/>
</Grid.Background>
<!-- Add controls as needed -->
</Grid>
<!-- Use whatever layout you need -->
<ContentControl x:Name="MainContent" />
</Grid>

Controls in the same cell of a Grid are rendered back-to-front. So a simple way to put one control on top of another is to put it in the same cell.
Here's a useful example, which pops up a panel that disables everything in the view (i.e. the user control) with a busy message while a long-running task is executed (i.e. while the BusyMessage bound property isn't null):
<Grid>
<local:MyUserControl DataContext="{Binding}"/>
<Grid>
<Grid.Style>
<Style TargetType="Grid">
<Setter Property="Visibility"
Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding BusyMessage}"
Value="{x:Null}">
<Setter Property="Visibility"
Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Border HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="DarkGray"
Opacity=".7" />
<Border HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
Padding="20"
BorderBrush="Orange"
BorderThickness="4">
<TextBlock Text="{Binding BusyMessage}" />
</Border>
</Grid>
</Grid>

Put the control you want to bring to front at the end of your xaml code. I.e.
<Grid>
<TabControl ...>
</TabControl>
<Button Content="ALways on top of TabControl Button"/>
</Grid>

This is a common function of Adorners in WPF. Adorners typically appear above all other controls, but the other answers that mention z-order may fit your case better.

<Canvas Panel.ZIndex="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="570">
<!-- YOUR XAML CODE -->
</Canvas>

Related

Is it possible to change properties of a resource instantiated with StaticResource element in XAML?

With this piece of XAML:
<Window.Resources>
<Rectangle x:Key="rectangle" x:Shared="False" Width="20" Height="8" Fill="Red" />
</Window.Resources>
<StaticResource x:Name="r1" ResourceKey="rectangle" />
<StaticResource x:Name="r2" ResourceKey="rectangle" />
it is possible to assign a value to say, Margin property, to each instance independently by code:
r1.Margin = 2;
r2.Margin = 5;
Is it possible to do it directly in XAML? I tried:
<StaticResource ResourceKey="rectangle" Margin="3"/>
but Margin is not a property of StaticResource...
Rephrasing after the XY problem sensor fired (appropriately)!
I want to draw rectangles with exactly the same properties except one, e.g. the margin or the color, in order to be able to change the shared properties centrally and still be able to provide specific properties in XAML. Can I use a resource like in my attempt?
Adding my exact need and code as suggested by comments
My exact need is to show the effect of setting different properties to some rectangle, i.e. changing Rectangle.RenderTransformOrigin and Rectangle.RenderTransform to compare effects. It's indeed to learn WPF, not for a production application. At the moment, I use a style (rotated) as I wasn't able to use a resource (this is the reason of my question above).
<Window x:Class="Test.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"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
Title="Transform Center" Height="400" Width="600">
<Window.Resources>
<Style x:Key="title" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Margin" Value="0,0,0,10" />
</Style>
<Style x:Key="rotated" TargetType="Rectangle">
<Setter Property="Width" Value="201" />
<Setter Property="Height" Value="81" />
<Setter Property="Fill" Value="CadetBlue"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
<Style x:Key="fixed" TargetType="Rectangle">
<Setter Property="Width" Value="30" />
<Setter Property="Height" Value="30" />
<Setter Property="Fill" Value="Indigo" />
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</Window.Resources>
<Grid >
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Background="Beige" Margin="5">
<Rectangle Style="{StaticResource fixed}" />
<Rectangle Style="{StaticResource rotated}" />
</StackPanel>
<TextBlock Grid.Row="0" Grid.Column="0"
Style="{StaticResource title}" Text="No rotation" />
<StackPanel Grid.Row="0" Grid.Column="1" Background="Beige" Margin="5">
<Rectangle Style="{StaticResource fixed}" />
<Rectangle Style="{StaticResource rotated}">
<Rectangle.RenderTransformOrigin>.5,.5</Rectangle.RenderTransformOrigin>
<Rectangle.RenderTransform>
<RotateTransform Angle="20" />
</Rectangle.RenderTransform>
</Rectangle>
</StackPanel>
<TextBlock Grid.Row="0" Grid.Column="1"
Style="{StaticResource title}"
Text="RenderTransformOrigin" />
<StackPanel Grid.Row="1" Grid.Column="0" Background="Beige" Margin="5">
<Rectangle Style="{StaticResource fixed}" />
<Rectangle Style="{StaticResource rotated}">
<Rectangle.RenderTransform>
<RotateTransform Angle="20" CenterX="100" CenterY="40" />
</Rectangle.RenderTransform>
</Rectangle>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0"
Style="{StaticResource title}"
Text="RotateTransform Center" />
<!-- The center coordinates relative to the Rectangle are the sum
of both center coordinates, i.e. .5 + .5 = 1 (bottom-right corner) -->
<StackPanel Grid.Row="1" Grid.Column="1" Background="Beige" Margin="5">
<Rectangle Style="{StaticResource fixed}" />
<Rectangle Style="{StaticResource rotated}">
<Rectangle.RenderTransformOrigin>.5,.5</Rectangle.RenderTransformOrigin>
<Rectangle.RenderTransform>
<RotateTransform Angle="20" CenterX="100" CenterY="40" />
</Rectangle.RenderTransform>
</Rectangle>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="1"
Style="{StaticResource title}"
Text="Both" />
</Grid>
</Window>
Does XAML allows to change a property of a resource when it is instantiated with <StaticResource>
Short answer: No.
The StaticResource markup extension simply references a resource based on a key. It can't change any properties of the resolved resource. You will have to set the properties of the resolved resource itself by for example casting the target property of the resource to a Rectangle.
I want to draw rectangles with exactly the same properties except one, e.g. the margin or the color
That sounds like a style to me. In WPF, there are usually several different ways to accomplish the same thing, and this is no exception.
it seems setting up a view-model is a bit oversized
Maybe. Maybe not. It's hard to say, as there aren't any other details in your question. That said, given the problem statement above, I'd agree it's certainly not necessary, and absent any other requirements, I don't see anything to be gained by using view models.
Even so, here's a code example that shows three different ways, two of which are based on view models and templates:
<Window x:Class="TestSO58683029RectStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:p="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"
xmlns:l="clr-namespace:TestSO58683029RectStyle"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:MainViewModel>
<l:MainViewModel.Rectangle1>
<l:RectangleViewModel Margin="2"/>
</l:MainViewModel.Rectangle1>
<l:MainViewModel.Rectangle2>
<l:RectangleViewModel Margin="5"/>
</l:MainViewModel.Rectangle2>
</l:MainViewModel>
</Window.DataContext>
<Window.Resources>
<p:Style TargetType="Rectangle">
<Setter Property="Width" Value="20"/>
<Setter Property="Height" Value="8"/>
<Setter Property="Fill" Value="Red"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</p:Style>
<DataTemplate DataType="{x:Type l:RectangleViewModel}">
<Rectangle Width="20" Height="8" Fill="Red" HorizontalAlignment="Left" Margin="{Binding Margin}"/>
</DataTemplate>
<x:Array x:Key="rectangleArray1" Type="{x:Type l:RectangleViewModel}">
<l:RectangleViewModel Margin="2"/>
<l:RectangleViewModel Margin="5"/>
</x:Array>
</Window.Resources>
<StackPanel>
<!-- Uses style -->
<Rectangle/>
<Rectangle Margin="2"/>
<Rectangle Margin="5"/>
<!-- Uses view models, individual properties -->
<ContentControl Content="{Binding Rectangle1}"/>
<ContentControl Content="{Binding Rectangle2}"/>
<!-- Uses view models, collection -->
<ItemsControl ItemsSource="{StaticResource rectangleArray1}"/>
</StackPanel>
</Window>
The view model approaches rely on these classes (they don't implement INotifyPropertyChanged, because there's no need in this simple example):
class RectangleViewModel
{
public Thickness Margin { get; set; }
}
class MainViewModel
{
public RectangleViewModel Rectangle1 { get; set; }
public RectangleViewModel Rectangle2 { get; set; }
}
As you can see, in the case of the style-based approach, a single <Style/> element in the resource dictionary can be used to define the default values for any properties you like. Then you can explicitly use a <Rectangle/> element where you want it in the content of your window, setting any other property explicitly. You can even override properties that were set in the style, if that's needed for any reason.
Note that in the above, the data template explicitly sets its property values. But you can actually combine the two techniques, by referring to the style resource when you declare the template, like so:
<DataTemplate DataType="{x:Type l:RectangleViewModel}">
<Rectangle Margin="{Binding Margin}" Style="{StaticResource ResourceKey={x:Type Rectangle}}"/>
</DataTemplate>
As noted in the comments, declaring concrete UI elements as resources is generally the wrong way to do something in WPF. I hesitate to say it's always wrong, but I would say it's almost always wrong. Concrete UI elements should be declared as actual content in the XAML, with styles used to provide default formatting for those elements. Otherwise you should be using templates, and allow WPF to create the UI elements as needed, based on the template you provide.

Wpf change the background colour of an expander's header only

I have looked at many questions/answers but couldn't find what I was exactly looking for,
I am trying to change the background colour of the expander's header only and not have the same colour continue for the content within the expander. Preferably within xaml but a vb.net solution would suffice.
(Any comments or suggestions will be helpful)
If this is a duplicated question please direct me to the answer and leave the question open to help others avoid the same issue in the future!
Thanks.
I am not sure whether this is what you are exactly looking for, but you could change the header background by simply doing that:
<Expander VerticalAlignment="Center">
<Expander.Header>
<Grid Background="LightBlue">
<TextBlock Text="Expander Header"/>
</Grid>
</Expander.Header>
<StackPanel>
<TextBlock Text="Cotent"></TextBlock>
</StackPanel>
</Expander>
Or you could override the default Expander's Header DataTemplate by using HeaderTemplate
<Window.Resources>
<DataTemplate x:Key="HeaderText">
<Border Height="25" Background="LightBlue">
<TextBlock Text="{Binding}"
Margin="4 0"
VerticalAlignment="Center"
Foreground="White"
FontSize="11"
FontWeight="Normal"
/>
</Border>
</DataTemplate>
<Style TargetType="{x:Type Expander}">
<Setter Property="HeaderTemplate" Value="{StaticResource HeaderText}"/>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Expander VerticalAlignment="Center" Header="Expander Header">
<StackPanel>
<TextBlock Text="Cotent"></TextBlock>
</StackPanel>
</Expander>
</Grid>
I had a lot of problems with getting the header background set.
I found the easiets weay to do it was to simply make a coloured rectangle and put it behind the expander. (use Margin and Height to make it fit)
<Rectangle Grid.Row="1" Grid.Column="0" Fill="LightBlue" Height="33" Margin="0,0,0,-35" />
or use a border if you want rounded corners:
<Border CornerRadius="15" Height="33" Margin="0,0,0,-35" Background="LightBlue" />

Icon DataTemplate for Icon MenuItem

I create some graphics for menuitem.icon.
<DataTemplate x:Key="navigation_arrow">
<DockPanel LastChildFill="True" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Canvas>
<Rectangle Fill="Red" Width="30" Height="20"/>
</Canvas>
</Grid>
</DockPanel>
</DataTemplate>
And then I try use this template for menuitem.icon
<MenuItem Header="" Icon="{Binding navigation_arrow}"/>
But it is empty menuitem. If I insert template code in MenuItem.Icon all work good
First: your binding is wrong. You must use this key as {DynamicResource navigation_arrow} or {StaticResource navigation_arrow}.
But It's not working. Your icon will be "System.Windows.DataTemplate" string, in this case.
DataTemplate means "It will apply a template for a data". You haven't got Data for Icon, so it cannot apply template for this.
You have to add concrete item as icon (like you mentioned) or create a style for it:
<Style TargetType="MenuItem">
<Setter Property="Icon">
<Setter.Value>
<DockPanel LastChildFill="True" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid>
<Canvas>
<Rectangle Fill="Red" Width="30" Height="20"/>
</Canvas>
</Grid>
</DockPanel>
</Setter.Value>
</Setter>
</Style>
but the fancy way is:
use DrawingBrush from resource
You can use a ContentControl:
<MenuItem.Icon>
<ContentControl ContentTemplate="{StaticResource navigation_arrow}"/>
</MenuItem.Icon>

Borderless ImageButtons in WrapPanel

I am attempting to create a WrapPanel with seamless ImageButtons containing Artwork. I put together the following ContentTemplate in the hopes that it would provide the seamless look required; however a thin white-line remained around each of the buttons. Can anyone steer me in the right direction?
<Button.ContentTemplate>
<DataTemplate DataType="{x:Type local:ArtInfo}">
<Border Name="border" BorderThickness="0" BorderBrush="blue" Height="280" Width="250" Background="#262c40">
<StackPanel>
<Grid>
<Grid.Resources>
<local:MyConverter x:Key="MyConverter"></local:MyConverter>
<ObjectDataProvider x:Key="Properties.Settings" ObjectType="{x:Type lcl:Properties.Settings}" />
</Grid.Resources>
<Image Name="ArtImage" Margin="10,15,0,0" Height="195" Width="195" VerticalAlignment="Top" >
<Image.Source>
<Binding Path="ArtImage"/>
</Image.Source>
</Image>
</Grid>
<TextBlock Text="{Binding Path=ArtClass}" Margin="10,-17,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="{Binding Path=Student}" Margin="10,0,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="1998" Margin="10,0,0,0" FontSize="11" Foreground="white" />
</StackPanel>
</Border>
</DataTemplate>
</Button.ContentTemplate>
The ContentTemplate tells WPF how to display the content within the Button -- the Button chrome (such as the border and background) remains, and the templated content is displayed within and over that chrome.
You want to replace the entire appearance of the Button, border and all, rather than just customising how its content is displayed. To do this, you need to use the Template property instead. The value of Button.Template is a ControlTemplate rather than a DataTemplate. Within that ControlTemplate, you can use the ContentPresenter to display the "data-templated" content.
In your case, since your DataTemplate is doing all the work, you could get away with a raw ContentPresenter as your template:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
However, if all your buttons are using the same background, you could move this into the ControlTemplate:
<Button.Template>
<ControlTemplate TargetType="Button">
<Border BorderBrush="Blue" ...>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
You could then remove the Border from the DataTemplate. This would really only matter if you were planning to reuse the same Button.Template with other content templates and wanted to keep the appearance of the Button consistent across different kinds of content.
create a usercontrol, put the botton & image in a grid.
<Grid>
<Image Source="icon.png" Panel.ZIndex="1" />
<Button
Panel.ZIndex="2"
FocusVisualStyle="{x:Null}"
Background="Transparent"/>
</Grid>

WPF: When is a WrapPanel full

I'm using a WrapPanel to display variable height items in columns. The wrappanel has a constrained size.
Is there an way to determine when the WrapPanel is 'full'? I will then page to another panel with an animation.
I've looked at the ArrangeOverride of the items that are the panels children, but they always seem to be getting all the space they want. I need a way to determine when they begin getting clipped.
Here's an example using a ScrollViewer with a trigger to determine whether it would display using ScrollableHeight. Right now it just changes some text but you could do other things. Removing one of the Rectangles will fire the trigger:
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="100" Height="50">
<ScrollViewer x:Name="scrollViewer" VerticalScrollBarVisibility="Hidden">
<WrapPanel>
<Rectangle Width="50" Height="20" Fill="Red"/>
<Rectangle Width="50" Height="20" Fill="Blue"/>
<Rectangle Width="50" Height="20" Fill="Green"/>
<Rectangle Width="50" Height="20" Fill="Yellow"/>
<Rectangle Width="50" Height="20" Fill="Orange"/>
</WrapPanel>
</ScrollViewer>
<TextBlock IsHitTestVisible="False">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="Clipped"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=scrollViewer, Path=ScrollableHeight}" Value="0">
<Setter Property="Text" Value="Not Clipped"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
You could also trigger based on ScrollViewer.ComputedVerticalScrollBarVisibility, but that requires the ScrollBar to actually be visible, whereas when you trigger based on ScrollableHeight, the ScrollBar can be hidden.
Actually using a WrapPanel for what you are trying to achieve doesn't seem like a good idea.
"[...] I will then page to another panel with an animation."
This would be layout to layout animation what isn't to easy, too.
You should write your own panel class: see here or (animated) here

Resources