Search code examples
c#wpfblurry

layered window with blur effect


I really like the effect that can be seen for example in iOS, which basicaly looks like a layer drawn on top of current view , bluring the visual content and using that as a background. Is there a way to achieve something like that in WPF?

iOS

I've seen people mostly dealing with this blur/transparency on Window level, but I need it within the window.

Let's say this is the content of my window.

<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
        <Image  Source="pack://application:,,,/Resources/Penguins.jpg"/>
        <Image  Source="pack://application:,,,/Resources/Penguins.jpg"/>
</StackPanel>

Which looks like

No layer

And now I'd like to draw something on top of that which ( instead of using red background ) blures whatever is beneath it and uses it as background, keeping it's content not blury.

    <DockPanel Margin="15" Background="Red">
        <StackPanel Orientation="Horizontal"  VerticalAlignment="Center" HorizontalAlignment="Center">
            <Label Content="Some label"/>
            <TextBox Width="100" Height="20"/>
        </StackPanel>
    </DockPanel>

Blur layer


Solution

  • Result:

    WPF with blurred background

    • We will use layering in a Grid. Background: Your main application content. Foreground: Your pseudo-dialog that will have a blurred background.

    • We will put the background in a border and refer to this border by its name. This will be used in a VisualBrush and provide our to-be-blurred image.

    • The foreground will also be a layered grid. Background: A rectangle, filled with the brush and using a blur effect. Foreground: Whatever you want to be in front.

      1. Add a reference to System.Windows.Interactivity.

      2. Add the following behavior code:

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Windows;
        using System.Windows.Controls;
        using System.Windows.Data;
        using System.Windows.Interactivity;
        using System.Windows.Media;
        using System.Windows.Media.Effects;
        using System.Windows.Shapes;
        
        namespace WpfApplication1
        {
            public class BlurBackgroundBehavior : Behavior<Shape>
            {
                public static readonly DependencyProperty BlurContainerProperty
                    = DependencyProperty.Register(
                                                  "BlurContainer",
                                                  typeof (UIElement),
                                                  typeof (BlurBackgroundBehavior),
                                                  new PropertyMetadata(OnContainerChanged));
        
                private static readonly DependencyProperty BrushProperty
                    = DependencyProperty.Register(
                                                  "Brush",
                                                  typeof (VisualBrush),
                                                  typeof (BlurBackgroundBehavior), 
                                                  new PropertyMetadata());
        
                private VisualBrush Brush
                {
                    get { return (VisualBrush) this.GetValue(BrushProperty); }
                    set { this.SetValue(BrushProperty, value); }
                }
        
                public UIElement BlurContainer
                {
                    get { return (UIElement) this.GetValue(BlurContainerProperty); }
                    set { this.SetValue(BlurContainerProperty, value); }
                }
        
                protected override void OnAttached()
                {
                    this.AssociatedObject.Effect = new BlurEffect
                                                   {
                                                       Radius = 80,
                                                       KernelType = KernelType.Gaussian,
                                                       RenderingBias = RenderingBias.Quality
                                                   };
        
                    this.AssociatedObject.SetBinding(Shape.FillProperty,
                                                     new Binding
                                                     {
                                                         Source = this,
                                                         Path = new PropertyPath(BrushProperty)
                                                     });
        
                    this.AssociatedObject.LayoutUpdated += (sender, args) => this.UpdateBounds();
                    this.UpdateBounds();
                }
        
                protected override void OnDetaching()
                {
                    BindingOperations.ClearBinding(this.AssociatedObject, Border.BackgroundProperty);
                }
        
                private static void OnContainerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
                {
                    ((BlurBackgroundBehavior) d).OnContainerChanged((UIElement) e.OldValue, (UIElement) e.NewValue);
                }
        
                private void OnContainerChanged(UIElement oldValue, UIElement newValue)
                {
                    if (oldValue != null)
                    {
                        oldValue.LayoutUpdated -= this.OnContainerLayoutUpdated;
                    }
        
                    if (newValue != null)
                    {
                        this.Brush = new VisualBrush(newValue)
                                     {
                                         ViewboxUnits = BrushMappingMode.Absolute
                                     };
        
                        newValue.LayoutUpdated += this.OnContainerLayoutUpdated;
                        this.UpdateBounds();
                    }
                    else
                    {
                        this.Brush = null;
                    }
                }
        
                private void OnContainerLayoutUpdated(object sender, EventArgs eventArgs)
                {
                    this.UpdateBounds();
                }
        
                private void UpdateBounds()
                {
                    if (this.AssociatedObject != null && this.BlurContainer != null && this.Brush != null)
                    {
                        Point difference = this.AssociatedObject.TranslatePoint(new Point(), this.BlurContainer);
                        this.Brush.Viewbox = new Rect(difference, this.AssociatedObject.RenderSize);
                    }
                }
            }
        }
        
      3. Use it in XAML like this:

        <Grid>
        
            <Border x:Name="content">
                <Border.Background>
                    <ImageBrush ImageSource="bild1.jpg" />
                </Border.Background>
        
                <StackPanel>
                    <TextBox Width="200" Margin="10" />
                    <TextBox Width="200" Margin="10" />
                    <TextBox Width="200" Margin="10" />
                </StackPanel>
            </Border>
        
            <Grid Margin="59,63,46,110"> 
        
                <Rectangle ClipToBounds="True">
                    <i:Interaction.Behaviors>
                        <wpfApplication1:BlurBackgroundBehavior BlurContainer="{Binding ElementName=content}" />
                    </i:Interaction.Behaviors>
                </Rectangle>
        
                <TextBox VerticalAlignment="Center" Text="Blah" Width="200" Height="30" />
        
            </Grid>
        
        </Grid>