i'm building a similar effect which AERO glass gives you, a blurred window. I quickly realized that is not easy in WPF, but i managed to get it to work almost completely.
I'm just stuck when a Viewbox is involved.
So what i did was: I created a rectangle, made a visual brush to take a portion of a given background element, convert the viewbox to take exactly the space of the image that the rectangle overlaps and use that as the fill for the rectangle.
<Grid x:Name="grid">
<Image x:Name="image" Source="someImage.png"/>
<Rectangle x:Name="blurBackgroundRect" Width="100" Height="100">
<Rectangle.Effect>
<BlurEffect Radius="10"/>
</Rectangle.Effect>
<Rectangle.Fill>
<VisualBrush
ViewboxUnits="Absolute"
AlignmentX="Center"
AlignmentY="Center"
Visual="{Binding ElementName=image}"
Stretch="None">
<VisualBrush.Viewbox>
<MultiBinding Converter="{StaticResource visualBrushTargetConverter}">
<Binding ElementName="grid"/>
<Binding ElementName="blurBackgroundRect"/>
<Binding ElementName="grid" Path="ActualWidth"/>
<Binding ElementName="grid" Path="ActualHeight"/>
</MultiBinding>
</VisualBrush.Viewbox>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
The ElementName grid, referes to the common parent of my rectangle and my image. I cant make them ancestors, otherwise it would interfere with the blur effect. So i place them next to each other in a grid.
The final part is the Multivalue converter, which does the actual calculation for the VisualBrush Viewbox.
public class VisualBrushTargetConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var parentControl = values[0] as FrameworkElement;
var targetControl = values[1] as FrameworkElement;
var transformedPos = targetControl.TransformToVisual(parentControl).Transform(new Point());
var transformedSize = targetControl.TransformToVisual(parentControl).Transform(new Point(targetControl.RenderSize.Width, targetControl.RenderSize.Height));
transformedSize = new Point(transformedSize.X - transformedPos.X, transformedSize.Y - transformedPos.Y);
return new Rect(transformedPos.X,
transformedPos.Y,
transformedSize.X,
transformedSize.Y);
}
}
So this is all necessary to reproduce my following problem. If you want to test the code, you can easily place that into a simple wpf application.
If you test this, you see that it works fine. The problem occurs now if we place the rectangle inside a Viewbox and a grid with a fixed size (which mimics my actual problem).
<Image x:Name="image" .../>
<Viewbox>
<Grid Width="800" Height="600">
<Rectangle x:Name="blurBackgroundRect" ...>
</Grid>
</Viewbox>
So im guessing that the scaling from the viewbox is applied after the layouting, thus won't get recognized in my TransformTo calls. But i already tried to use the actual scaling of the Viewbox in my convert, but to no luck. As long as the Viewbox is there, i can't get it to work, so i hope anybody has an idea what could be wrong, or maybe even point me to a much simpler solution.
I want that code to later convert to a custom control, to easily reuse that, so i prefere ways that don't rely to much on any special conditions.
See Question&Answers more detail:
os