Wpf how to create inner shadow like a sunken border - wpf

I am trying to accomplish the inner shadow in the following image.
It is a sort of sunken border looking shadow. I managed to come close with linear gradient fill but it needs some blur.
<Style TargetType="{x:Type local:LargeLabelWithUnitControl}">
<Setter Property="MaxHeight" Value="80"/>
<Setter Property="MinHeight" Value="80"/>
<Setter Property="MaxWidth" Value="130"/>
<Setter Property="MinWidth" Value="130"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LargeLabelWithUnitControl}">
<Border BorderThickness="6" CornerRadius="15" >
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="10"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Display the LabelText -->
<TextBlock Text="{Binding LabelText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:LargeLabelWithUnitControl}}"
Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="Center"
FontSize="50"
FontFamily="Calibri"/>
<!-- Display the UnitText -->
<TextBlock Text="{Binding UnitText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:LargeLabelWithUnitControl}}"
Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="Center"
FontSize="20"
FontFamily="Calibri"/>
</Grid>
</Border>
<Border.BorderBrush>
<LinearGradientBrush StartPoint="0, 0" EndPoint="0.3, 0.8" >
<GradientStop Color="#ff095750" Offset="0.0"/>
<GradientStop Color="#ff148F7F" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Anyone knows how to do this?

So I have been on a quest to find a good answer to this very problem. So far there doesn't seem to be an easy or clean answer. This link here is good if your shape doesn't have rounded corners(or you want shading on all sides as seen in the rectangle example). https://www.codeproject.com/Articles/225076/Creating-Inner-Shadows-for-WPF-and-Silverlight
Though there doesn't seem to be a good solution for what you want. I have found something that works for my purposes, though it's not pretty in the slightest!
<Grid>
<Border Background="Yellow" Width="30" Height="30" Margin="-2" BorderThickness="2" CornerRadius="7" >
<!-- This blue border is hidden by the grey border -->
<Border Background="Transparent" BorderBrush="Blue" BorderThickness="1,1,0,0" CornerRadius ="5">
<Border.Effect>
<!-- This is where the actual inneshadow is defined -->
<DropShadowEffect ShadowDepth="0" BlurRadius="4" Color ="Red"/>
</Border.Effect>
</Border>
</Border>
<!-- Keeps blur radius from leaking out Normally it would be the color of the background -->
<Border BorderBrush="Green" Margin="-3" BorderThickness="3" CornerRadius="7" />
<!-- Grey border : If you want a borderless look I would recommend changing
this border to the background color as well or changing the size and
coverage of the green border -->
<Border BorderThickness="1" CornerRadius ="5" BorderBrush="Grey" />
</Grid>
Here is a link to the results https://imgur.com/zFh30jb, I added wacky colors so it should be clear which part is which. Again this is not a perfect solution and if anyone has anything better I would be interested. You will have to mess around with it a bit to get it to work for your purposes.
But I hope this helps someone out there!

Related

WPF toolkit, shared tooltip between multiple lineseries

I'm working with multiple time-series chart based on WPF toolkit. For example time-series of temperature, dewpoint and pressure in one chart
I need to share tooltips to show at each datapoint a summary of the meteorlogical parameters at a certain date/time in a little tooltip frame.
If anyone know if it is possible and how to do that, it would be great.
Thanks,
PY
Look up Styles for the DataPoints of your Series i've got one example for BubbleDataSeries:
<Style x:Key="BubbleToolTipTemplate" TargetType="{x:Type c:BubbleDataPoint}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="c:BubbleDataPoint">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" />
<ContentPresenter Content="{TemplateBinding Size}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<ToolTipService.ToolTip>
<StackPanel>
<ContentControl Content ="{TemplateBinding DependentValue, Converter={StaticResource DoubleToStringConverter}}" />
<ContentControl Content ="{TemplateBinding IndependentValue}"/>
<ContentControl Content ="{TemplateBinding Size}" />
</StackPanel>
</ToolTipService.ToolTip>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Round a arbitrary content control

I have an Esri ArcGis map control which I want to round around the edges. I am also using Prism4.0/MEF and SL4.
I tried to place it in a border, but that doesn't work (the Esri control is loaded into the MapRegion, in another module):
<Border Grid.Row="2"
Margin="2"
CornerRadius="25">
<ContentControl
prism:RegionManager.RegionName="MapRegion"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch">
</ContentControl>
</Border>
UPDATE: Looks like this is not possible. This isn't really a bug with the Map itself, but it kind of is. The Map uses a Canvas inside the Grid "RootElement". This Canvas holds the images for the map. When using a Canvas, it doesn't respect the bounds it's been given. You can reproduce the bug with the following XAML
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="25">
<Grid>
<Grid>
<Canvas>
<Image Source="/Images/MyPicture.png"/>
</Canvas>
</Grid>
</Grid>
</Border>
The best approach is going to be to set an explicit style for the map. With this style any map that is used will have the rounded corners
<Style TargetType="esri:Map">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="esri:Map">
<Border CornerRadius="25" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<Grid>
<Grid x:Name="RootElement" Height="Auto" Width="Auto"/>
<Rectangle x:Name="ZoomBox" Fill="#55FFFFFF" Stroke="Red" StrokeThickness="2" Visibility="Collapsed"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF custom progress bar clipping

I've created a custom progress bar as follows:
<!-- Custom progress bar -->
<Style
x:Key="CopyProgressBar"
TargetType="ProgressBar">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="ProgressBar">
<Grid>
<Border
x:Name="PART_Track"
CornerRadius="5"
BorderBrush="#BBC6C4"
BorderThickness="2" />
<Rectangle
x:Name="PART_Indicator"
Fill="#A5B2B0"
RadiusX="5"
RadiusY="5"
Margin="3"
HorizontalAlignment="Left" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here's how it is used:
<ProgressBar
x:Name="copyProgress"
Height="13"
Width="279"
Canvas.Left="158"
Canvas.Top="103"
Minimum="0"
Maximum="100"
Style="{StaticResource CopyProgressBar}" />
It works quite well, but when the progress is full, the right side of the fill bar is clipped, which removes the rounding styling I'm going for. I've fiddled with padding, margins, max width, etc, but I can't find a way to prevent the clipping.
Here is an image:
This was an interesting one to answer. I finally got it nailed down to being the margin that was causing the problem. The progress bar sets the width of PART_Indicator based on the width of PART_Track regardless of the margin or paddings that are set. The following style will get you the desired behaviour.
<Style x:Key="CopyProgressBar" TargetType="ProgressBar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border BorderBrush="#BBC6C4" BorderThickness="1" CornerRadius="5" Padding="1">
<Grid x:Name="PART_Track" >
<Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#A5B2B0" RadiusX="5" RadiusY="5"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF: How can I remove the searchbox in a DocumentViewer?

My XAML code is like this:
<Window
xmlns ='http://schemas.microsoft.com/netfx/2007/xaml/presentation'
xmlns:x ='http://schemas.microsoft.com/winfx/2006/xaml'
Title ='Print Preview - More stuff here'
Height ='200'
Width ='300'
WindowStartupLocation ='CenterOwner'>
<DocumentViewer Name='dv1' ... />
</Window>
How can I, in XAML or in C#, eliminate the search box?
You can do something similar to Cheeso's answer with a style for ContentControl and a trigger to hide it when the name is PART_FindToolBarHost.
<DocumentViewer>
<DocumentViewer.Resources>
<Style TargetType="ContentControl">
<Style.Triggers>
<Trigger Property="Name" Value="PART_FindToolBarHost">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</DocumentViewer.Resources>
</DocumentViewer>
Vlad's answer led me to look at how to programmatically grab the ContentControl that holds the find toolbar. I didn't really want to write an entirely new template for the DocumentViewer; I wanted to change (hide) only one control. That reduced the problem to how to retrieve a control that is applied via a template?.
Here's what I figured out:
Window window = ... ;
DocumentViewer dv1 = LogicalTreeHelper.FindLogicalNode(window, "dv1") as DocumentViewer;
ContentControl cc = dv1.Template.FindName("PART_FindToolBarHost", dv1) as ContentControl;
cc.Visibility = Visibility.Collapsed;
As Vlad pointed out you can replace the control template. Unfortunately, the control template available on MSDN is not the real control template used by the DocumentViewer control. Here is the correct template modified to hide the search bar by setting Visibility="Collapsed" on PART_FindToolBarHost:
<!-- DocumentViewer style with hidden search bar. -->
<Style TargetType="{x:Type DocumentViewer}" xmlns:Documents="clr-namespace:System.Windows.Documents;assembly=PresentationUI">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="ContextMenu" Value="{DynamicResource {ComponentResourceKey ResourceId=PUIDocumentViewerContextMenu, TypeInTargetAssembly={x:Type Documents:PresentationUIStyleResources}}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DocumentViewer}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Focusable="False">
<Grid Background="{TemplateBinding Background}" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentControl Grid.Column="0" Focusable="{TemplateBinding Focusable}" Grid.Row="0" Style="{DynamicResource {ComponentResourceKey ResourceId=PUIDocumentViewerToolBarStyleKey, TypeInTargetAssembly={x:Type Documents:PresentationUIStyleResources}}}" TabIndex="0"/>
<ScrollViewer x:Name="PART_ContentHost" CanContentScroll="true" Grid.Column="0" Focusable="{TemplateBinding Focusable}" HorizontalScrollBarVisibility="Auto" IsTabStop="true" Grid.Row="1" TabIndex="1"/>
<DockPanel Grid.Row="1">
<FrameworkElement DockPanel.Dock="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}"/>
<Rectangle Height="10" Visibility="Visible" VerticalAlignment="top">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="#66000000" Offset="0"/>
<GradientStop Color="Transparent" Offset="1"/>
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</DockPanel>
<ContentControl x:Name="PART_FindToolBarHost" Grid.Column="0" Focusable="{TemplateBinding Focusable}" Grid.Row="2" TabIndex="2" Visibility="Collapsed"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You need to add a reference to PresentationUI.dll. This assembly is located in the folder %WINDIR%\Microsoft.NET\Framework\v4.0.30319\WPF.
You can replace a control template for it. For your reference: the default DocumentViewer's control template is here: http://msdn.microsoft.com/en-us/library/aa970452.aspx
The search toolbar's name is PART_FindToolBarHost, so you can also just assign its Visibility to Collapsed.
Edit:
As the comment from #Martin suggests, the control template in MSDN (referenced above) is not fully correct. A better way to extract a template which is actually used in WPF by default would be using Blend (Edit Control Template in the context menu, if I am not mistaken).
In order to get Cheeso's answer to work in the constructor I had to add:
dv1.ApplyTemplate();
otherwise cc comes out null. See the answer here
<DocumentViewer>
<DocumentViewer.Resources>
<!-- Toolbar -->
<Style TargetType="ToolBar">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
<!-- Search -->
<Style TargetType="ContentControl">
<Setter Property="Visibility" Value="Collapsed" />
</Style>
</DocumentViewer.Resources>
</DocumentViewer>
Are you sure you need a DocumentViewer? You could use a FlowDocumentScrollViewer instead, or if you like pagination or multi-column display, you could use a FlowDocumentPageViewer.

WPF DropShadow Disappears

Wpf dropshadow disappears.
Here is how to reproduce.
Type the following in xaml pad.
<Page.Resources>
<DropShadowEffect x:Key="shadow"
Opacity="1"
ShadowDepth="1"
Color="Blue"
BlurRadius="30"/>
</Page.Resources>
<Grid>
<Button HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Bd"
BorderBrush="Black" BorderThickness="1"
Background="Yellow"
CornerRadius="8"
Effect="{StaticResource shadow}">
<TextBlock Text="Hello out there" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</Grid>
You should see some text with a border abound it, and a drop shadow around the border.
Now change the Margin="0,0,0,0" to Margin="0,300,0,0", and size your xaml pad window so you can see the border. On my machine, the drop shadow is now gone.
Anyone else see this? Please help.
I wish I had a good explanation for you, but there were some weird things in your XAML that I played with and I think I have a solution for you.
If you use a Grid, most likely you want to lay out a specific number of rows and columns. You should specify those. This doesn't affect your problem, however.
Likewise, you should specify the Row and Column for your element because you'll eventually need to put this information in your XAML anyway. It's a good habit to start with IMO.
The problem that I can't explain is with the combination of HorizontalAlignment and VerticalAlignment. When you put the Button in the Grid, I would expect the Button to take up the entire space, but it doesn't. The only way you can make this work as far as I could figure out was to specify Height and Width. If you do this, the Effect will work. I found that the threshold in your original XML was a total Y margin of 239. For example, if you used 0,239,0,0, it would fail. If you used 0,139,0,100, it would also fail because the sum is 239. Weird stuff.
Here's my XAML that works:
<Page.Resources>
<DropShadowEffect x:Key="shadow"
Opacity="1"
ShadowDepth="2"
Color="Blue"
BlurRadius="30"/>
</Page.Resources>
<Grid Width="Auto" Height="Auto">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Width="90" Height="30" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,300,0,0" Grid.Row="0" Grid.Column="0">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Bd"
BorderBrush="Black" BorderThickness="1"
Background="Yellow"
CornerRadius="8"
Effect="{StaticResource shadow}">
<TextBlock Text="Hello out there" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
EDIT The OP does not want to specify a size for the Button because the Content of the Button can change dynamically. It turns out that if you set the MinHeight to something like 18 (I think this is reasonable for most content), the dropshadow effect will work again.
<Border x:Name="Bd" BorderBrush="Black" BorderThickness="1" Background="Yellow" CornerRadius="8" Effect="{StaticResource shadow}" MinHeight="18">
<StackPanel Orientation="Vertical">
<TextBlock>hi</TextBlock>
<TextBlock>there</TextBlock>
</StackPanel>
</Border>

Resources