具有模糊效果的分层窗口

6
我非常喜欢在iOS中看到的效果,它基本上看起来像是在当前视图之上绘制的一层,模糊了视觉内容并将其用作背景。有没有办法在WPF中实现类似的效果?
我看到大多数人主要处理窗口级别的模糊/透明度,但我需要在窗口内部实现。
假设这是我的窗口内容。
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
        <Image  Source="pack://application:,,,/Resources/Penguins.jpg"/>
        <Image  Source="pack://application:,,,/Resources/Penguins.jpg"/>
</StackPanel>

这个看起来像:

没有图层

现在我想在它上面画一些东西,使用底部的内容作为背景,模糊底部的内容而不是使用红色背景,使它的内容清晰可见。

    <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


http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/403/Glass-Behavior-for-WPF.aspx - Federico Berasategui
@HighCore,我已经尝试过那个项目了,但它似乎更像玻璃效果而不是模糊效果,我一直没有能够获得期望的效果。我做错了什么吗? - pikausp
你可以在行为中应用任何效果。只需使用适当的BlurRadius应用BlurEffect,就可以开始了。 - Federico Berasategui
设置这些根本没有任何效果,您介意花点功夫下载示例项目并截取屏幕截图展示一下它在您的屏幕上的样子吗? - pikausp
1个回答

6

结果:

带模糊背景的WPF

  • 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>
      

i 被定义为什么? - pikausp
刚刚弄明白了,非常感谢Frank,这正是我所需要的,再次感谢Frank! - pikausp
实际上,我刚刚注意到一个性能问题,当我试图调整表单大小时,这可以消除吗? - pikausp
在BlurEffect的初始化器中尝试使用KernelType.Box。不幸的是,有高半径的BlurEffect非常消耗性能。 - Frank
嗯,我不是很喜欢盒子类型,但由于模糊效果不会一直可见,所以我认为这不会成为问题。我使用了一个底层矩形作为模糊的背景层,背景颜色为灰色,这使得它看起来更好。 - pikausp
有没有一种方法可以均匀地模糊并且不具备径向笔刷效果? - LueTm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接