I am trying to create a blur effect in WPF, but I want to blur the content located behind the control (such as a Grid), I do not intend to blur the contents of the Grid.
I want to do something like this image.
If you are looking for something like this:
The answer is to use a BitmapEffect :
<Image Source="http://www.pingminghealth.com/wp-content/uploads/2010/12/cherries.jpg" Stretch="UniformToFill">
<Image.BitmapEffect>
<BlurBitmapEffect Radius="20" />
</Image.BitmapEffect>
</Image>
You can find a tutorial about it on msdn: How to Apply a Blur Effect to a Visual.
Just in case, someone is still looking for a solution in 2018, something like this worked for me: BlurryControls.BlurryUserControl.cs
<Rectangle>
<Rectangle.Effect>
<BlurEffect Radius="{DynamicResource BlurRadius}"/>
</Rectangle.Effect>
<Rectangle.Fill>
<VisualBrush
ViewboxUnits="Absolute"
Viewbox="{Binding RenderTransform.Children[3],
Converter={StaticResource TranslateTransformToRectViewboxVisualBrushConverter},
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}},
UpdateSourceTrigger=PropertyChanged}"
AlignmentX="Left" AlignmentY="Top"
Visual="{Binding ElementName=BackgroundContainer}" Stretch="None">
<VisualBrush.Transform>
<TranslateTransform X="0" />
</VisualBrush.Transform>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
I found here that the DropShadows can't overflow over component with a fixed Height.
I tried to add somme ClipToBounds="False" in every containers but it doesn't seems to work.
you will see the problem if you create a new project with this code :
<Window .... >
<StackPanel x:Name="Sp2" Margin="20" Height="47" ClipToBounds="False">
<Rectangle Height="40" Fill="Purple" Margin="4" ClipToBounds="False">
<Rectangle.Effect>
<DropShadowEffect Opacity=".4" BlurRadius="13" ShadowDepth="4" Direction="288"/>
</Rectangle.Effect>
</Rectangle>
</StackPanel>
</Window>
Here is a screenshot of the problem :
On the left that's what i want, a shadow overflowing on a fixed height component, and on the right that's what i have.
As I work in a team and I'm developping every UI components for our application and I'd like other people of my team not to have to pay attention to these kind of details. How can we avoid this behavior, and if we can't what would be the guidelines to avoid this clipping effect ?
You can override GetLayoutClip() to stop most things clipping.
As explained here.
http://drwpf.com/blog/2007/12/28/cliptoboundsmaybe/
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace wpf_99
{
public class NoClipStackPanel : StackPanel
{
protected override Geometry GetLayoutClip(Size layoutSlotSize)
{
return ClipToBounds ? base.GetLayoutClip(layoutSlotSize) : null;
}
}
}
Markup
<Grid>
<local:NoClipStackPanel x:Name="Sp2" Margin="20" Height="47" ClipToBounds="False">
<Rectangle Height="40" Fill="Purple" Margin="4" ClipToBounds="False">
<Rectangle.Effect>
<DropShadowEffect Opacity=".4" BlurRadius="13" ShadowDepth="4" Direction="288"/>
</Rectangle.Effect>
</Rectangle>
</local:NoClipStackPanel>
</Grid>
One possibility to solve this issue is similar to solution of another problem, when trying to apply effects to control containing text and text become blurred. The idea is to detach effect, by applying it to something else, while ensuring that visually it looks like effect was applied to where you need it.
In your case you can do something like this:
<Grid>
<Rectangle Width="{Binding ActualWidth, ElementName=rect}"
Height="{Binding ActualHeight, ElementName=rect}"
Fill="Green">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="30" />
</Rectangle.Effect>
</Rectangle>
<StackPanel Margin="20" Height="47">
<Rectangle x:Name="rect" Height="40" Fill="Purple" Margin="4">
<!-- remove effect from here -->
</Rectangle>
</StackPanel>
</Grid>
The effect is not anymore on nested rectangle, but on some element (I've used Rectangle) which is added below StackPanel (since its transparent) in visual tree. If you do it like this than shadow can now extend itself to whole grid (which takes whole window size).
I am working on a product in WPF that requires an end-user toolbox, exactly like Visual Studio, where the user can drag and drop specific tools (such as a Button) onto another Canvas object.
So far, I have it looking OK, and am using the official Microsoft vector icons next to a label describing the tool.
For example, the code below displays a vector button icon and a label next to it.
My question is, how do I group both the image and label together so that they are "one item", similar to the Visual Studio toolbox.
I need the two grouped items to be draggable/droppable onto a separate Canvas object.
I don't have much experience with this in WPF so any advice would be appreciated.
<Viewbox
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Width="16"
Height="16"
Grid.Row="1"
Grid.Column="0">
<Rectangle
Width="16"
Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing
Brush="#00FFFFFF"
Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing
Brush="#FFF6F6F6"
Geometry="F1M2.5857,-0.000199999999999534L-0.000299999999999745,2.5858 -0.000299999999999745,9.4138 2.5857,12.0008 7.9997,12.0008 7.9997,14.2418 9.4317,14.2418 10.3357,13.2478 11.2607,15.3318 14.2687,13.9638 13.4017,11.9978 15.3537,11.9978 15.3537,10.5318 15.1097,10.3048 16.0007,9.4138 16.0007,2.5858 13.4147,-0.000199999999999534z" />
<GeometryDrawing
Brush="#FF424242"
Geometry="F1M9,6L9,13.23 10.629,11.441 11.766,14.004 12.955,13.463 11.869,10.998 14.387,10.998z M8,11L3,11 1,9 1,3 3,1 13,1 15,3 15,9 14.376,9.624 13.642,8.943 14,8.586 14,3.414 12.586,2 3.414,2 2,3.414 2,8.586 3.414,10 8,10z" />
<GeometryDrawing
Brush="#FFF0EFF1"
Geometry="F1M8,10L3.414,10 2,8.586 2,3.414 3.414,2 12.586,2 14,3.414 14,8.586 13.642,8.943 8,3.708z" />
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
<Label
Content="Button"
Grid.Row="1"
VerticalContentAlignment="Center"
Grid.ColumnSpan="2"
Margin="29,0,2.6,0.4" />
I have a DrawingImage that I use as a Vector image placeholder.
Further on, there are styles that take that respective DrawingImage and use it as an image in my UserControl custom button.
So far everything was fine, but I just came to realize that my current approach has caused my DrawingImages to be non-reusable, since they have their Brush property hard-bound to the control, they are used in, as follows:
<DrawingImage x:Key="addIcon">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{Binding Path=ImageBrush, ElementName=addButton}" Geometry="M438.2,0H51.6C23.1,0,0,23.2,0,51.6v386.6c0,28.5,23.2,51.6,51.6,51.6h386.6c28.5,0,51.6-23.2,51.6-51.6V51.6
C489.8,23.2,466.6,0,438.2,0z M465.3,438.2c0,14.9-12.2,27.1-27.1,27.1H51.6c-14.9,0-27.1-12.2-27.1-27.1V51.6
c0-14.9,12.2-27.1,27.1-27.1h386.6c14.9,0,27.1,12.2,27.1,27.1V438.2z" />
<GeometryDrawing Brush="{Binding Path=ImageBrush, ElementName=addButton}" Geometry="M337.4,232.7h-80.3v-80.3c0-6.8-5.5-12.3-12.3-12.3s-12.3,5.5-12.3,12.3v80.3h-80.3c-6.8,0-12.3,5.5-12.3,12.2
c0,6.8,5.5,12.3,12.3,12.3h80.3v80.3c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-80.3h80.3c6.8,0,12.3-5.5,12.3-12.3
C349.7,238.1,344.2,232.7,337.4,232.7z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
Now, I was trying to come up with a way to have them bound not directly to the Element, but to some kind of a generic Element (similairly as interfaces work) so that the code would be sure that anything that is bound to it, has got the Brush Dependency property.
So far, i failed to find it.
I have also tried by searching through an ancestor, still no luck.
Is there a more or less common practice to binding to unknown Elements, that have certain dependency properties, without exposing them directly?
In fact, there is no way to do directly what you ask. The reason is that when you define DrawingImage as a resource and then use it as a source for image, then no copies of the resource are created, but instead of this each image looks at the same resource. Therefore, the DrawingImage can not have a parent in the visual tree at all, so there is just no control to bind to.
There are two options here. One is to use a Geometry as a resource, not a DrawingImage. Then you can create some DrawingImage resources referencing to this Geometry and using different colors. Or do not use DrawingImage at all, but use the Geometry directly (for example, through the Path). Actually, there are so many ways how to use and combine Geometry resources. I give just few examples here:
<Window x:Class="FlipControlApp.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"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<PathGeometry x:Key="addIconGeometry" Figures="M337.4,232.7h-80.3v-80.3c0-6.8-5.5-12.3-12.3-12.3s-12.3,5.5-12.3,12.3v80.3h-80.3c-6.8,0-12.3,5.5-12.3,12.2
c0,6.8,5.5,12.3,12.3,12.3h80.3v80.3c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-80.3h80.3c6.8,0,12.3-5.5,12.3-12.3
C349.7,238.1,344.2,232.7,337.4,232.7z"/>
<PathGeometry x:Key="iconBorderGeometry" Figures="M438.2,0H51.6C23.1,0,0,23.2,0,51.6v386.6c0,28.5,23.2,51.6,51.6,51.6h386.6c28.5,0,51.6-23.2,51.6-51.6V51.6
C489.8,23.2,466.6,0,438.2,0z M465.3,438.2c0,14.9-12.2,27.1-27.1,27.1H51.6c-14.9,0-27.1-12.2-27.1-27.1V51.6
c0-14.9,12.2-27.1,27.1-27.1h386.6c14.9,0,27.1,12.2,27.1,27.1V438.2z"/>
<GeometryGroup x:Key="addIconWithBorderGeometry">
<StaticResource ResourceKey="iconBorderGeometry"/>
<StaticResource ResourceKey="addIconGeometry"/>
</GeometryGroup>
<DrawingImage x:Key="addIconBlack">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Black" Geometry="{StaticResource addIconWithBorderGeometry}" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
<UniformGrid Columns="2">
<Button Name="addButton0" Width="100" Height="100">
<Image Source="{StaticResource addIconBlack}"/>
</Button>
<Button Width="100" Height="100" Foreground="Blue">
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control}}"
Geometry="{StaticResource addIconGeometry}" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Button>
<Button Width="100" Height="100" Foreground="Green">
<Grid>
<Path Data="{StaticResource iconBorderGeometry}" Fill="Pink" Stretch="Uniform"/>
<Path Data="{StaticResource addIconGeometry}" Fill="Purple" Stretch="Uniform" Margin="15"/>
</Grid>
</Button>
<Button x:Name="addBtn" Width="100" Height="100" Foreground="Green">
<Path Fill="{Binding Foreground, ElementName=addBtn}" Stretch="Uniform">
<Path.Data>
<CombinedGeometry Geometry1="{StaticResource iconBorderGeometry}" Geometry2="{StaticResource addIconGeometry}"/>
</Path.Data>
</Path>
</Button>
</UniformGrid>
</Window>
Another option is to use whole Image as resource with a Brush binding to the some ancestors property. But in this case, it is necessary to use the attribute x:Shared and hence the resource must be declared in the compiled resource dictionary (for details see x:Shared).
Create resource:
<ResourceDictionary>
<Image x:Key="addIconImage2" x:Shared="False">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control}}"
Geometry="M438.2,0H51.6C23.1,0,0,23.2,0,51.6v386.6c0,28.5,23.2,51.6,51.6,51.6h386.6c28.5,0,51.6-23.2,51.6-51.6V51.6
C489.8,23.2,466.6,0,438.2,0z M465.3,438.2c0,14.9-12.2,27.1-27.1,27.1H51.6c-14.9,0-27.1-12.2-27.1-27.1V51.6
c0-14.9,12.2-27.1,27.1-27.1h386.6c14.9,0,27.1,12.2,27.1,27.1V438.2z" />
<GeometryDrawing Brush="{Binding Foreground, RelativeSource={RelativeSource AncestorType=Control}}"
Geometry="M337.4,232.7h-80.3v-80.3c0-6.8-5.5-12.3-12.3-12.3s-12.3,5.5-12.3,12.3v80.3h-80.3c-6.8,0-12.3,5.5-12.3,12.2
c0,6.8,5.5,12.3,12.3,12.3h80.3v80.3c0,6.8,5.5,12.3,12.3,12.3s12.3-5.5,12.3-12.3v-80.3h80.3c6.8,0,12.3-5.5,12.3-12.3
C349.7,238.1,344.2,232.7,337.4,232.7z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</ResourceDictionary>
Then use it:
<Button Name="addButton3" Width="100" Height="100"
Content="{StaticResource addIconImage}" Foreground="Red"/>
<Button Name="addButton4" Width="100" Height="100"
Content="{StaticResource addIconImage}" Foreground="Green"/>
Each time you reference to it, new copy will be created.
But the first way is more flexible.
I have made a small cross icon using a polygon as following:
<Viewbox Margin="28,-22,-28,22">
<Polygon
Points="300, 200 325,200 325,250 375,250 375,275 325,275 325,325 300,325 300,275 250,275 250,250 300,250 300,200" Height="513" Width="595">
<Polygon.Fill>
<SolidColorBrush Color="#666666" Opacity="100"/>
</Polygon.Fill>
<Polygon.RenderTransform>
<RotateTransform CenterX="313" CenterY="237" Angle="45" />
</Polygon.RenderTransform>
</Polygon>
</Viewbox>
Now I want this polygon to be loaded into my button. How can I do this?
Put that inside Button.Content:
<Button ...>
<Viewbox ...>
</Viewbox>
</Button>
Don't forget to remove ViewBox.Margin (make Button big enough) or make it negative.