c# - UWP 组合 - 带圆角的网格 DropShadow
问题描述
我有一个 UWP 应用程序,我应该首先指出它使用很少的 XAML。视图是根据从 API 接收的 JSON 对象构建的。这意味着绝大多数事情都是在 C# 中完成的,因此给我的问题增加了一点复杂性。
我基本上想要一个面板(例如网格),它可以有圆角并应用投影。阴影也应该有圆角,这可以在下面的示例中看到。
我已经将 DropShadowPanel 视为Windows Community Toolkit的一部分,但据我所知,除非我将内容更改为矩形或其他形状,否则它不会做圆角。
将其用作解决方案意味着 XAML 等效于以下内容:
<Grid>
<toolkit:DropShadowPanel>
<Rectangle />
<toolkit:DropShadowPanel>
<Grid CornerRadius="30">
<!-- My Content -->
</Grid>
</Grid>
对我来说,这似乎是对 XAML 的低效使用!
我还发现了Composition Pro Toolkit,对我来说它看起来很有趣,因为它是所有代码。特别是 ImageFrame 控件看起来可以实现我所需要的基础 - 尽管比我的需要先进得多。
以下基于 ImageFrame,但不起作用(content
是我的网格):
protected FrameworkElement AddDropShadow(FrameworkElement content)
{
var container = new Grid { HorizontalAlignment = content.HorizontalAlignment, VerticalAlignment = content.VerticalAlignment, Width = content.Width, Height = content.Height };
var canvas = new Canvas { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };
content.Loaded += (s, e) =>
{
var compositor = ElementCompositionPreview.GetElementVisual(canvas).Compositor;
var root = compositor.CreateContainerVisual();
ElementCompositionPreview.SetElementChildVisual(canvas, root);
var shadowLayer = compositor.CreateSpriteVisual();
var frameLayer = compositor.CreateLayerVisual();
var frameContent = compositor.CreateShapeVisual();
root.Children.InsertAtBottom(shadowLayer);
root.Children.InsertAtTop(frameLayer);
frameLayer.Children.InsertAtTop(frameContent);
var rectangle = root.Compositor.CreateRoundedRectangleGeometry();
rectangle.Size = new Vector2((float)content.ActualWidth, (float)content.ActualHeight);
rectangle.CornerRadius = new Vector2(30f);
var shape = root.Compositor.CreateSpriteShape(rectangle);
shape.FillBrush = root.Compositor.CreateColorBrush(Colors.Blue);
//var visual = root.Compositor.CreateShapeVisual();
frameContent.Size = rectangle.Size;
frameContent.Shapes.Add(shape);
//create mask layer
var layerEffect = new CompositeEffect
{
Mode = Microsoft.Graphics.Canvas.CanvasComposite.DestinationIn,
Sources = { new CompositionEffectSourceParameter("source"), new CompositionEffectSourceParameter("mask") }
};
var layerEffectFactory = compositor.CreateEffectFactory(layerEffect);
var layerEffectBrush = layerEffectFactory.CreateBrush();
//CompositionDrawingSurface
var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, new Microsoft.Graphics.Canvas.CanvasDevice(forceSoftwareRenderer: false));
var frameLayerMask = graphicsDevice.CreateDrawingSurface(new Size(0, 0), Windows.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized, Windows.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
layerEffectBrush.SetSourceParameter("mask", compositor.CreateSurfaceBrush(frameLayerMask));
frameLayer.Effect = layerEffectBrush;
var shadow = root.Compositor.CreateDropShadow();
//shadow.SourcePolicy = CompositionDropShadowSourcePolicy.InheritFromVisualContent;
shadow.Mask = layerEffectBrush.GetSourceParameter("mask");
shadow.Color = Colors.Black;
shadow.BlurRadius = 25f;
shadow.Opacity = 0.75f;
shadow.Offset = new Vector3(0, 0, 0);
shadowLayer.Shadow = shadow;
content.Opacity = 0; //hiding my actual content to see the results of this
};
container.Children.Add(canvas);
container.Children.Add(content);
return container;
}
在这些测试中,我对对象的使用同样低效,创建了另一个容器,该容器既具有合成画布,又具有网格。如果可能,我想将合成直接应用于原始内容网格。
我对作文完全陌生,所以任何想法、指示、明显的错误或解决方案都将受到欢迎。
黑客解决方案?
我已将我的方法更改为以下,视觉上它有效 - 但它是对的吗?
protected FrameworkElement AddDropShadow(FrameworkElement content)
{
var container = new Grid { HorizontalAlignment = content.HorizontalAlignment, VerticalAlignment = content.VerticalAlignment };
var rectangle = new Rectangle { Fill = new SolidColorBrush(Colors.Transparent) };
content.Loaded += (s, e) =>
{
rectangle.Fill = new SolidColorBrush(Colors.Black);
rectangle.Width = content.ActualWidth;
rectangle.Height = content.ActualHeight;
rectangle.RadiusX = 30;
rectangle.RadiusY = 30;
var compositor = ElementCompositionPreview.GetElementVisual(rectangle).Compositor;
var visual = compositor.CreateSpriteVisual();
visual.Size = new Vector2((float)content.ActualWidth, (float)content.ActualHeight);
var shadow = compositor.CreateDropShadow();
shadow.BlurRadius = 30f;
shadow.Mask = rectangle.GetAlphaMask();
shadow.Opacity = 0.75f;
visual.Shadow = shadow;
ElementCompositionPreview.SetElementChildVisual(rectangle, visual);
};
container.Children.Add(rectangle);
container.Children.Add(content);
return container;
}
这里的概念是我的container
网格包含一个rectangle
和我的content
网格(或其他元素)。
这种方法的第一个错误是假设我的输入FrameworkElement
是矩形的。我想这可以通过创建此博客content
中突出显示的位图渲染来改进- 但这可能会非常昂贵。我还必须确保矩形的大小和形状与我的主要内容完全匹配!
屏幕上画了一个矩形感觉很不对劲(尽管被我的主要内容隐藏了)。矩形纯粹是为了创建 alpha 蒙版,所以我想如果蒙版是从内容的渲染中创建的,它可能会被废弃。
我尝试将矩形的可见性设置为折叠以将其从视觉树中删除。这意味着我可以将视觉对象附加到容器:
ElementCompositionPreview.SetElementChildVisual(container, visual)
但是,这样做意味着阴影会显示在主要内容的前面,这意味着我也需要一些其他的 ui 元素来附加它——也可能是矩形!
解决方案
您使用的解决方案是我当前的解决方法,我需要在orRectangle
下的圆形阴影。这很简单,很简单,我为什么要抱怨 :) 但如果这不是你的选择,你可以画一个圆角矩形并模糊它:Grid
Border
GraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(Compositor, CanvasDevice.GetSharedDevice());
var roudRectMaskSurface = GraphicsDevice.CreateDrawingSurface(new Size(SurfaceWidth + BlurMargin * 2, SurfaceHeight + BlurMargin * 2), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);
using (var ds = CanvasComposition.CreateDrawingSession(roudRectMaskSurface))
{
ds.Clear(Colors.Transparent);
ds.FillRoundedRectangle(new Rect(BlurMargin, BlurMargin, roudRectMaskSurface.Size.Width + BlurMargin, roudRectMaskSurface.Size.Height + BlurMargin), YourRadius, YourRadius, Colors.Black);
}
var rectangleMask = Compositor.CreateSurfaceBrush(roudRectMaskSurface);
现在您可以在模糊效果中应用此表面EffectBrush
以获得自定义阴影。
BlurMargin
- 对应于模糊量,您需要它,因为您的模糊表面将大于初始源矩形(以避免模糊剪辑)。
推荐阅读
- java - 在JPA中如何不让孩子的孩子......等的孩子?
- c# - 将接口的实现委托给其他对象的最佳实践——使用实现其他接口的接口
- html - 为什么我的提交按钮没有提交表单数据?- HTML/节点
- laravel - 此路由不支持 GET 方法。支持的方法:laravel 中的 POST
- python-3.x - Tkinter 将方法绑定到空格键
- java - Spring Boot 中使用的 System.getenv() 在 sonarQube 中显示为安全漏洞
- python-3.x - 无法使用 astropy.io 的拟合打印整个数据集
- reactjs - 如何拆分 API 获取的链接并在 React JS 中显示图像
- makefile - makefile 规则中的目标顺序是否重要?
- c++ - const char* 的属性是什么?