многослойное окно с эффектом размытия

Мне очень нравится эффект, который можно увидеть, например, в iOS, который в основном выглядит как слой, нарисованный поверх текущего вида, размывающий визуальный контент и использующий его в качестве фона. Есть ли способ добиться чего-то подобного в WPF?

iOS

Я видел, как люди в основном имеют дело с этим размытием/прозрачностью на уровне окна, но мне это нужно в окне.

Допустим, это содержимое моего окна.

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

Размытие слоя


person pikausp    schedule 11.12.2014    source источник
comment
jmorrill.hjtcentral.com/Home/ tabid/428/EntryId/403/   -  person Federico Berasategui    schedule 12.12.2014
comment
@HighCore Я уже пробовал этот проект, но он кажется скорее стеклянным, чем размытым, и мне не удалось получить желаемый эффект. Я делаю что-то не так?   -  person pikausp    schedule 12.12.2014
comment
Вы можете применять любые эффекты в поведении. Просто примените BlurEffect с правильным BlurRadius, и все готово.   -  person Federico Berasategui    schedule 12.12.2014
comment
Их установка не имеет никакого эффекта, не могли бы вы приложить усилия, загрузить пример проекта и сделать снимок экрана, как он выглядит на вашем экране?   -  person pikausp    schedule 12.12.2014


Ответы (1)


Результат:

WPF с размытым фоном

  • Мы будем использовать слои в сетке. Фон: основное содержимое вашего приложения. Передний план: ваш псевдодиалог с размытым фоном.

  • Мы поместим фон в рамку и будем ссылаться на эту рамку по ее имени. Это будет использовано в VisualBrush и обеспечит наше размытое изображение.

  • Передний план также будет многослойной сеткой. Фон: прямоугольник, заполненный кистью и использующий эффект размытия. Передний план: все, что вы хотите быть впереди.

    1. Добавьте ссылку на System.Windows.Interactivity.

    2. Добавьте следующий код поведения:

      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. Используйте его в XAML следующим образом:

      <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>
      
person Frank    schedule 12.12.2014
comment
Как определяется i? - person pikausp; 12.12.2014
comment
Только что понял, большое спасибо, Фрэнк, это именно то, что мне было нужно, спасибо, Фрэнк! - person pikausp; 12.12.2014
comment
На самом деле я только что заметил проблему с производительностью, когда пытаюсь изменить размер формы, можно ли от этого избавиться? - person pikausp; 13.12.2014
comment
Попробуйте KernelType.Box в инициализаторе BlurEffect. BlurEffect с большим радиусом, к сожалению, очень требователен к производительности. - person Frank; 13.12.2014
comment
Ммм, мне не очень нравится тип коробки, но поскольку размытие не будет видно все время, я думаю, это не будет такой проблемой. Я использовал еще 1 прямоугольник в качестве нижнего слоя для размытия с серым цветом фона, так как это делает его еще лучше. - person pikausp; 13.12.2014
comment
Есть ли способ равномерно размыть и теперь иметь этот эффект радиальной кисти? - person LueTm; 28.03.2018