Размытие фона с помощью Viewbox

я создаю эффект, который дает вам стекло AERO, размытое окно. Я быстро понял, что это нелегко в WPF, но мне удалось заставить его работать почти полностью. Я просто застрял, когда включен Viewbox.

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

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

Сетка ElementName ссылается на общего родителя моего прямоугольника и моего изображения. Я не могу сделать их предками, иначе это помешает эффекту размытия. Поэтому я размещаю их рядом друг с другом в сетке.

Последняя часть - это многозначный конвертер, который выполняет фактические вычисления для 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);
    }
}

Так что это все необходимое, чтобы воспроизвести мою следующую проблему. Если вы хотите протестировать код, вы можете легко поместить его в простое приложение wpf.

Если вы проверите это, вы увидите, что он работает нормально. Проблема возникает сейчас, если мы поместим прямоугольник в Viewbox и сетку с фиксированным размером (что подражает моей реальной проблеме).

<Image x:Name="image" .../>
<Viewbox>
    <Grid Width="800" Height="600">
        <Rectangle x:Name="blurBackgroundRect" ...>
    </Grid>
</Viewbox>

Поэтому я предполагаю, что масштабирование из окна просмотра применяется после компоновки, поэтому не будет распознаваться в моих вызовах TransformTo. Но я уже пытался использовать фактическое масштабирование Viewbox в моем конверте, но безуспешно. Пока есть Viewbox, я не могу заставить его работать, поэтому я надеюсь, что у кого-нибудь есть идея, что может быть не так, или, может быть, даже укажете мне на гораздо более простое решение. Я хочу, чтобы этот код впоследствии преобразовывался в пользовательский элемент управления, чтобы его можно было легко использовать повторно, поэтому я предпочитаю способы, которые не слишком зависят от каких-либо особых условий.

Ответы на вопрос(1)

Ваш ответ на вопрос