我有以下玻璃效果,改编自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>
这会产生
这很棒,但是我想将这个模糊应用到我正在使用的可移动ContentControl
,以便我可以将控件拖到图像上,并模糊/编辑某个人脸,以便转动此图像< / p>
进入此图像(注意模糊的脸)。
为此,我尝试在上面的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
,以便移动的控件在悬停的图像上投射所需的模糊?