WPF中可移动物体的Vista玻璃效果

时间:2018-01-13 23:08:50

标签: c# wpf xaml effects

我有以下玻璃效果,改编自WPF-MediaKit,其代码为

    public class GlassBehavior : Behavior<FrameworkElement>
    {
        private FrameworkElement attachedObject;

        private readonly VisualBrush directVisualBrush = new VisualBrush();

        private readonly Rectangle surrogateVisual = new Rectangle();

        private readonly VisualBrush surrogateVisualBrush = new VisualBrush();

        public GlassBehavior()
        {
            RenderOptions.SetEdgeMode(directVisualBrush, EdgeMode.Aliased);
            RenderOptions.SetCachingHint(directVisualBrush, CachingHint.Cache);

            RenderOptions.SetEdgeMode(surrogateVisualBrush, EdgeMode.Aliased);
            RenderOptions.SetCachingHint(surrogateVisualBrush, CachingHint.Cache);

            directVisualBrush.Stretch = Stretch.None;

            surrogateVisualBrush.ViewboxUnits = BrushMappingMode.Absolute;
            surrogateVisualBrush.ViewportUnits = BrushMappingMode.RelativeToBoundingBox;
            surrogateVisualBrush.Viewport = new Rect(0, 0, 1, 1);
        }

        public static readonly DependencyProperty VisualProperty = DependencyProperty.Register("Visual",
            typeof(Visual), typeof(GlassBehavior), new FrameworkPropertyMetadata(
                null, new PropertyChangedCallback(OnVisualChanged)));

        public Visual Visual
        {
            get { return (Visual)GetValue(VisualProperty); }
            set { SetValue(VisualProperty, value); }
        }

        private static void OnVisualChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GlassBehavior)d).OnVisualChanged(e);
        }

        protected virtual void OnVisualChanged(DependencyPropertyChangedEventArgs e)
        {
            SetupVisual();
        }

        public static readonly DependencyProperty EffectProperty =
             DependencyProperty.Register("Effect", typeof(Effect), typeof(GlassBehavior),
                  new FrameworkPropertyMetadata(null,
                        new PropertyChangedCallback(OnEffectChanged)));

        public Effect Effect
        {
            get { return (Effect)GetValue(EffectProperty); }
            set { SetValue(EffectProperty, value); }
        }

        private static void OnEffectChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((GlassBehavior)d).OnEffectChanged(e);
        }

        protected virtual void OnEffectChanged(DependencyPropertyChangedEventArgs e)
        {
            SetEffect();
        }

        private void SetEffect()
        {
            if (surrogateVisual == null)
                return;

            surrogateVisual.Effect = Effect;
        }

        private void SetupVisual()
        {
            var element = Visual as FrameworkElement;
            if (element == null || attachedObject == null)
                return;

            SetEffect();

            surrogateVisualBrush.Visual = element;
            surrogateVisual.Fill = surrogateVisualBrush;

            directVisualBrush.Visual = surrogateVisual;
            EnsureBrushSyncWithVisual();
        }

        private void EnsureBrushSyncWithVisual()
        {
            if (attachedObject == null || Visual == null)
                return;

            surrogateVisual.Width = attachedObject.ActualWidth;
            surrogateVisual.Height = attachedObject.ActualHeight;

            GeneralTransform trans = attachedObject.TransformToVisual(Visual);
            Point pos = trans.Transform(new Point(0, 0));
            var viewbox = new Rect
            {
                X = pos.X,
                Y = pos.Y,
                Width = attachedObject.ActualWidth,
                Height = attachedObject.ActualHeight
            };
            surrogateVisualBrush.Viewbox = viewbox;
        }

        protected override void OnAttached()
        {
            if (attachedObject != null)
                attachedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;

            attachedObject = AssociatedObject;

            PropertyInfo info = FindFillProperty(attachedObject);
            if (info != null)
                info.SetValue(attachedObject, directVisualBrush, null);

            attachedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
            SetupVisual();
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            if (attachedObject != null)
                attachedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;

            base.OnDetaching();
        }

        private static PropertyInfo FindFillProperty(DependencyObject obj)
        {
            Type t = obj.GetType();
            PropertyInfo info = t.GetProperty("Background") ?? t.GetProperty("Fill");
            return info;
        }

        private void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
        {
            EnsureBrushSyncWithVisual();
        }
    }

然后我有以下XAML来采用这种效果

<Window ...>
    <Grid>
        <Grid x:Name="G0">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <Grid x:Name="G1" 
                  Margin="0,0,0,0"
                  Canvas.Left="0" 
                  Canvas.Top="0"
                  Width="{Binding ActualWidth, ElementName=C1}"
                  Height="{Binding ActualHeight, ElementName=C1}"
                  HorizontalAlignment="Stretch"
                  VerticalAlignment="Stretch">
                <Image Source="large-snow-leopard-portrait-chris-boulton.jpg" 
                       HorizontalAlignment="Stretch"
                       VerticalAlignment="Stretch"
                       Stretch="UniformToFill"/>
            </Grid>

            <Border Margin="479,10,10,10" 
                      Background="#FF545454" 
                      BorderBrush="#FF000000" 
                      BorderThickness="1,1,1,1" 
                      CornerRadius="8,8,8,8">
                <i:Interaction.Behaviors>
                    <Behaviors:GlassBehavior Visual="{Binding ElementName=G1, Mode=OneWay}">
                        <Behaviors:GlassBehavior.Effect>
                            <BlurEffect/>
                            <!--<ShaderEffectLibrary:PixelateEffect HorizontalPixelCounts="40" VerticalPixelCounts="40"/>-->
                        </Behaviors:GlassBehavior.Effect>
                    </Behaviors:GlassBehavior>
                </i:Interaction.Behaviors>
                <Border.Effect>
                    <DropShadowEffect BlurRadius="20" ShadowDepth="1"/>
                </Border.Effect>
                <Grid HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Button Grid.Row="0" Content="Button" Margin="30,0" Height="30"/>
                    <Button Grid.Row="1" Content="Button" Margin="30,0" Height="30"/>
                    <Button Grid.Row="2" Content="Button" Margin="30,0" Height="30"/>
                    <Button Grid.Row="3" Content="Button" Margin="30,0" Height="30"/>
                </Grid>
            </Border>
        </Grid>
    </Grid>
</Window>

这会产生

Snow Lepoard

这很棒,但是我想将这个模糊应用到我正在使用的可移动ContentControl,以便我可以将控件拖到图像上,并模糊/编辑某个人脸,以便转动此图像< / p>

Bun

进入此图像(注意模糊的脸)。

BlurBun

为此,我尝试在上面的XAML中添加Canvas,我们有

    ...
    <Grid>
        <Grid x:Name="G0">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid x:Name="G1" 
                  Margin="0,0,0,0"
                  Canvas.Left="0" 
                  Canvas.Top="0"
                  Width="{Binding ActualWidth, ElementName=C1}"
                  Height="{Binding ActualHeight, ElementName=C1}"
                  HorizontalAlignment="Stretch"
                  VerticalAlignment="Stretch">
                <Image Source="large-snow-leopard-portrait-chris-boulton.jpg" 
                       HorizontalAlignment="Stretch"
                       VerticalAlignment="Stretch"
                       Stretch="UniformToFill"/>
            </Grid>
            <Canvas x:Name="C1" 
                    Panel.ZIndex="1"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch">
                <ContentControl 
                            Width="130"
                            Height="130"
                            Canvas.Top="150"
                            Canvas.Left="150"
                            Selector.IsSelected="True"
                            Controls:TextBoxAttachedProperties.Text="Some Text Person #2"
                            Controls:TextBoxAttachedProperties.TextBoxBackground="DeepPink"
                            Controls:TextBoxAttachedProperties.TextBoxForeground="White" 
                            Controls:ResizeThumb.HandleForeground="#2D2D30" 
                            Controls:ResizeThumb.HandleForegroundHovered="#007ACC"
                            Controls:RotateThumb.HandleVisibility="Collapsed" 
                            Controls:RotateThumb.HandleForeground="#656565"
                            Controls:RotateThumb.HandleForegroundHovered="#007ACC"
                            Style="{StaticResource MoveResizeRotateItemStyle}">
                    <Border Background="#FF545454" >
                        <i:Interaction.Behaviors>
                            <Behaviors:GlassBehavior Visual="{Binding ElementName=G1, Mode=OneWay}">
                                <Behaviors:GlassBehavior.Effect>
                                    <ShaderEffectLibrary:PixelateEffect HorizontalPixelCounts="40" VerticalPixelCounts="40"/>
                                </Behaviors:GlassBehavior.Effect>
                            </Behaviors:GlassBehavior>
                        </i:Interaction.Behaviors>
                    </Border>
                </ContentControl>
            </Canvas>
        </Grid>
    </Grid>
</Window>

问题是,我从

中抛出了InvalidOperationException
GeneralTransform trans = attachedObject.TransformToVisual(Visual);

EnsureBrushSyncWithVisual()类的方法GlassBehavior中。

  

System.InvalidOperationException:&#39;指定的Visual和此Visual不共享一个共同的祖先,因此两个Visual之间没有有效的转换。&#39;

我的问题是

Q值。如何编辑GlassBehavior类,以便将此效果应用于我的可移动ContentControl,以便移动的控件在悬停的图像上投射所需的模糊?

0 个答案:

没有答案