Question

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.

Was it helpful?

Solution

I was able to fix the weird behaviour by changing the Stretch on the VisualBrush to Fill instead of None.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top