C# UWP 工具包 DropShadowPanel 内部阴影
C# UWP Toolkit DropShadowPanel inner shadow
在C# UWP中如何制作内阴影效果?
像这样:
我创建了一个只有边框的网格,但阴影填充了整个网格。
<controls:DropShadowPanel BlurRadius="5"
ShadowOpacity="0.5"
OffsetX="0"
OffsetY="0"
Color="Black">
<Grid BorderBrush="White" BorderThickness="5"/>
</controls:DropShadowPanel>
如何用这个控件制作内阴影效果?
请注意 DropShadowPanel
可以屏蔽 Rectangle
,因此您可以创建 fill-less Rectangle
并将其放在 DropShadowPanel
仅为 Rectangle
的 边界 创建扩展阴影。然后,您只需将它放在 Grid
内并剪裁 Grid
以切断外部阴影。如果您想要背景色,只需将另一个 Rectangle
添加到 Grid
并将其放在 DropShadowPanel
之后。
示例代码
<Grid Width="400"
Height="200"
Margin="24">
<Grid.Clip>
<RectangleGeometry Rect="0,0,400,200" />
</Grid.Clip>
<Rectangle x:Name="BackgroundColor"
Fill="LightSteelBlue" />
<controls:DropShadowPanel x:Name="InnerShadow"
HorizontalContentAlignment="Stretch"
BlurRadius="15"
ShadowOpacity="0.5"
Color="Black">
<Rectangle x:Name="BorderColor"
Stroke="LightGray"
StrokeThickness="10" />
</controls:DropShadowPanel>
</Grid>
结果
关于裁剪
需要注意的一件事是,只要 Grid
的大小发生变化,您就需要手动更新 Rect
的大小。或者,您可以使用新的 Composition API 进行裁剪 -
var visual = ElementCompositionPreview.GetElementVisual(RootGrid);
var compositor = visual.Compositor;
visual.Clip = compositor.CreateInsetClip();
protected override CreateParams CreateParams
{
get
{
const int CS_DROPSHADOW = 0x20000;
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CS_DROPSHADOW;
return cp;
}
}
我遇到了同样的问题,最后我为它创建了自己的控件。我基本上创建了一个带有四个细边框的网格,每边一个(左、右、上、下),每个边框都有一个线性渐变画笔来创建阴影效果。像这样:
这是代码::
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace TestInnerDropShadow
{
[TemplatePart(Name = PARTNAME_LEFT_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_RIGHT_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_TOP_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_BOTTOM_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_LEFT_GRADIENT, Type = typeof(GradientStop))]
[TemplatePart(Name = PARTNAME_RIGHT_GRADIENT, Type = typeof(GradientStop))]
[TemplatePart(Name = PARTNAME_TOP_GRADIENT, Type = typeof(GradientStop))]
[TemplatePart(Name = PARTNAME_BOTTOM_GRADIENT, Type = typeof(GradientStop))]
public class InnerDropShadowPanel : ContentControl
{
internal const string PARTNAME_LEFT_BORDER = "PART_LeftBorder";
internal const string PARTNAME_RIGHT_BORDER = "PART_RightBorder";
internal const string PARTNAME_TOP_BORDER = "PART_TopBorder";
internal const string PARTNAME_BOTTOM_BORDER = "PART_BottomBorder";
internal const string PARTNAME_LEFT_GRADIENT = "PART_LeftGradient";
internal const string PARTNAME_RIGHT_GRADIENT = "PART_RightGradient";
internal const string PARTNAME_TOP_GRADIENT = "PART_TopGradient";
internal const string PARTNAME_BOTTOM_GRADIENT = "PART_BottomGradient";
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
UpdateShadowDimensions();
UpdateShadowColor();
}
private static void OnPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is InnerDropShadowPanel thisControl)
{
var updateLeft = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusLeftProperty);
var updateRight = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusRightProperty);
var updateTop = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusTopProperty);
var updateBottom = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusBottomProperty);
thisControl.UpdateShadowDimensions(updateLeft, updateRight, updateTop, updateBottom);
}
}
private void UpdateShadowDimensions(bool updateLeft = true, bool updateRight = true, bool updateTop = true, bool updateBottom = true)
{
if (updateLeft && GetTemplateChild(PARTNAME_LEFT_BORDER) is Border left)
{
left.Width = BlurRadiusLeft;
left.Opacity = ShadowOpacity;
}
if (updateRight && GetTemplateChild(PARTNAME_RIGHT_BORDER) is Border right)
{
right.Width = BlurRadiusRight;
right.Opacity = ShadowOpacity;
}
if (updateTop && GetTemplateChild(PARTNAME_TOP_BORDER) is Border top)
{
top.Height = BlurRadiusTop;
top.Opacity = ShadowOpacity;
}
if (updateBottom && GetTemplateChild(PARTNAME_BOTTOM_BORDER) is Border bottom)
{
bottom.Height = BlurRadiusBottom;
bottom.Opacity = ShadowOpacity;
}
}
private void UpdateShadowColor()
{
if (GetTemplateChild(PARTNAME_LEFT_GRADIENT) is GradientStop left)
left.Color = ShadowColor;
if (GetTemplateChild(PARTNAME_RIGHT_GRADIENT) is GradientStop right)
right.Color = ShadowColor;
if (GetTemplateChild(PARTNAME_TOP_GRADIENT) is GradientStop top)
top.Color = ShadowColor;
if (GetTemplateChild(PARTNAME_BOTTOM_GRADIENT) is GradientStop bottom)
bottom.Color = ShadowColor;
}
#region ShadowOpacity Dependency Property
public static readonly DependencyProperty ShadowOpacityProperty = DependencyProperty.Register(
nameof(ShadowOpacity),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double ShadowOpacity
{
get => (double)GetValue(ShadowOpacityProperty);
set => SetValue(ShadowOpacityProperty, value);
}
#endregion
#region ShadowColor Dependency Property
public static readonly DependencyProperty ShadowColorProperty = DependencyProperty.Register(
nameof(ShadowColor),
typeof(Color),
typeof(InnerDropShadowPanel),
new PropertyMetadata(Colors.Transparent, OnShadowColorChanged));
public Color ShadowColor
{
get => (Color)GetValue(ShadowColorProperty);
set => SetValue(ShadowColorProperty, value);
}
private static void OnShadowColorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is InnerDropShadowPanel thisControl)
{
thisControl.UpdateShadowColor();
}
}
#endregion
#region BlurRadiusLeft Dependency Property
public static readonly DependencyProperty BlurRadiusLeftProperty = DependencyProperty.Register(
nameof(BlurRadiusLeft),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusLeft
{
get => (double)GetValue(BlurRadiusLeftProperty);
set => SetValue(BlurRadiusLeftProperty, value);
}
#endregion
#region BlurRadiusRight Dependency Property
public static readonly DependencyProperty BlurRadiusRightProperty = DependencyProperty.Register(
nameof(BlurRadiusRight),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusRight
{
get => (double)GetValue(BlurRadiusRightProperty);
set => SetValue(BlurRadiusRightProperty, value);
}
#endregion
#region BlurRadiusTop Dependency Property
public static readonly DependencyProperty BlurRadiusTopProperty = DependencyProperty.Register(
nameof(BlurRadiusTop),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusTop
{
get => (double)GetValue(BlurRadiusTopProperty);
set => SetValue(BlurRadiusTopProperty, value);
}
#endregion
#region BlurRadiusBottom Dependency Property
public static readonly DependencyProperty BlurRadiusBottomProperty = DependencyProperty.Register(
nameof(BlurRadiusBottom),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusBottom
{
get => (double)GetValue(BlurRadiusBottomProperty);
set => SetValue(BlurRadiusBottomProperty, value);
}
#endregion
}
}
以及控件模板:
<Style TargetType="local:InnerDropShadowPanel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:InnerDropShadowPanel">
<Grid>
<ContentPresenter/>
<Border x:Name="PART_LeftBorder"
Opacity="0.5"
HorizontalAlignment="Left"
VerticalAlignment="Stretch">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Black" Offset="0" x:Name="PART_LeftGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="PART_RightBorder"
Opacity="0.5"
HorizontalAlignment="Right"
VerticalAlignment="Stretch">
<Border.Background>
<LinearGradientBrush StartPoint="1,0" EndPoint="0,0">
<GradientStop Color="Black" Offset="0" x:Name="PART_RightGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="PART_TopBorder"
Opacity="0.5"
HorizontalAlignment="Stretch"
VerticalAlignment="Top">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Black" Offset="0" x:Name="PART_TopGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="PART_BottomBorder"
Opacity="0.5"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom">
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="Black" Offset="0" x:Name="PART_BottomGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background></Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
与 XAML 像这样:
<local:InnerDropShadowPanel HorizontalAlignment="Center"
BlurRadiusLeft="6"
BlurRadiusTop="6"
ShadowOpacity="0.4"
ShadowColor="Black">
<TextBlock Text="Test"
Foreground="Black"
FontSize="120"
Margin="50,20"/>
</local:InnerDropShadowPanel>
你得到这样的结果:
您可以在任何一侧或全部添加阴影,并整体更改阴影的颜色和不透明度:
<local:InnerDropShadowPanel HorizontalAlignment="Center"
BlurRadiusLeft="6"
BlurRadiusTop="6"
BlurRadiusBottom="50"
BlurRadiusRight="100"
ShadowOpacity="1"
ShadowColor="Red">
<TextBlock Text="Test"
Foreground="Black"
FontSize="120"
Margin="50,20"/>
</local:InnerDropShadowPanel>
给你这个:
我相信您可以修改此控件并通过添加自定义设置来发挥作用,例如,每一面都有不同的颜色或不透明度。不过,上述解决方案可能足以满足绝大多数情况。
在C# UWP中如何制作内阴影效果?
像这样:
我创建了一个只有边框的网格,但阴影填充了整个网格。
<controls:DropShadowPanel BlurRadius="5"
ShadowOpacity="0.5"
OffsetX="0"
OffsetY="0"
Color="Black">
<Grid BorderBrush="White" BorderThickness="5"/>
</controls:DropShadowPanel>
如何用这个控件制作内阴影效果?
请注意 DropShadowPanel
可以屏蔽 Rectangle
,因此您可以创建 fill-less Rectangle
并将其放在 DropShadowPanel
仅为 Rectangle
的 边界 创建扩展阴影。然后,您只需将它放在 Grid
内并剪裁 Grid
以切断外部阴影。如果您想要背景色,只需将另一个 Rectangle
添加到 Grid
并将其放在 DropShadowPanel
之后。
示例代码
<Grid Width="400"
Height="200"
Margin="24">
<Grid.Clip>
<RectangleGeometry Rect="0,0,400,200" />
</Grid.Clip>
<Rectangle x:Name="BackgroundColor"
Fill="LightSteelBlue" />
<controls:DropShadowPanel x:Name="InnerShadow"
HorizontalContentAlignment="Stretch"
BlurRadius="15"
ShadowOpacity="0.5"
Color="Black">
<Rectangle x:Name="BorderColor"
Stroke="LightGray"
StrokeThickness="10" />
</controls:DropShadowPanel>
</Grid>
结果
关于裁剪
需要注意的一件事是,只要 Grid
的大小发生变化,您就需要手动更新 Rect
的大小。或者,您可以使用新的 Composition API 进行裁剪 -
var visual = ElementCompositionPreview.GetElementVisual(RootGrid);
var compositor = visual.Compositor;
visual.Clip = compositor.CreateInsetClip();
protected override CreateParams CreateParams
{
get
{
const int CS_DROPSHADOW = 0x20000;
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CS_DROPSHADOW;
return cp;
}
}
我遇到了同样的问题,最后我为它创建了自己的控件。我基本上创建了一个带有四个细边框的网格,每边一个(左、右、上、下),每个边框都有一个线性渐变画笔来创建阴影效果。像这样:
这是代码::
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace TestInnerDropShadow
{
[TemplatePart(Name = PARTNAME_LEFT_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_RIGHT_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_TOP_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_BOTTOM_BORDER, Type = typeof(Border))]
[TemplatePart(Name = PARTNAME_LEFT_GRADIENT, Type = typeof(GradientStop))]
[TemplatePart(Name = PARTNAME_RIGHT_GRADIENT, Type = typeof(GradientStop))]
[TemplatePart(Name = PARTNAME_TOP_GRADIENT, Type = typeof(GradientStop))]
[TemplatePart(Name = PARTNAME_BOTTOM_GRADIENT, Type = typeof(GradientStop))]
public class InnerDropShadowPanel : ContentControl
{
internal const string PARTNAME_LEFT_BORDER = "PART_LeftBorder";
internal const string PARTNAME_RIGHT_BORDER = "PART_RightBorder";
internal const string PARTNAME_TOP_BORDER = "PART_TopBorder";
internal const string PARTNAME_BOTTOM_BORDER = "PART_BottomBorder";
internal const string PARTNAME_LEFT_GRADIENT = "PART_LeftGradient";
internal const string PARTNAME_RIGHT_GRADIENT = "PART_RightGradient";
internal const string PARTNAME_TOP_GRADIENT = "PART_TopGradient";
internal const string PARTNAME_BOTTOM_GRADIENT = "PART_BottomGradient";
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
UpdateShadowDimensions();
UpdateShadowColor();
}
private static void OnPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is InnerDropShadowPanel thisControl)
{
var updateLeft = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusLeftProperty);
var updateRight = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusRightProperty);
var updateTop = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusTopProperty);
var updateBottom = (e.Property == ShadowOpacityProperty || e.Property == BlurRadiusBottomProperty);
thisControl.UpdateShadowDimensions(updateLeft, updateRight, updateTop, updateBottom);
}
}
private void UpdateShadowDimensions(bool updateLeft = true, bool updateRight = true, bool updateTop = true, bool updateBottom = true)
{
if (updateLeft && GetTemplateChild(PARTNAME_LEFT_BORDER) is Border left)
{
left.Width = BlurRadiusLeft;
left.Opacity = ShadowOpacity;
}
if (updateRight && GetTemplateChild(PARTNAME_RIGHT_BORDER) is Border right)
{
right.Width = BlurRadiusRight;
right.Opacity = ShadowOpacity;
}
if (updateTop && GetTemplateChild(PARTNAME_TOP_BORDER) is Border top)
{
top.Height = BlurRadiusTop;
top.Opacity = ShadowOpacity;
}
if (updateBottom && GetTemplateChild(PARTNAME_BOTTOM_BORDER) is Border bottom)
{
bottom.Height = BlurRadiusBottom;
bottom.Opacity = ShadowOpacity;
}
}
private void UpdateShadowColor()
{
if (GetTemplateChild(PARTNAME_LEFT_GRADIENT) is GradientStop left)
left.Color = ShadowColor;
if (GetTemplateChild(PARTNAME_RIGHT_GRADIENT) is GradientStop right)
right.Color = ShadowColor;
if (GetTemplateChild(PARTNAME_TOP_GRADIENT) is GradientStop top)
top.Color = ShadowColor;
if (GetTemplateChild(PARTNAME_BOTTOM_GRADIENT) is GradientStop bottom)
bottom.Color = ShadowColor;
}
#region ShadowOpacity Dependency Property
public static readonly DependencyProperty ShadowOpacityProperty = DependencyProperty.Register(
nameof(ShadowOpacity),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double ShadowOpacity
{
get => (double)GetValue(ShadowOpacityProperty);
set => SetValue(ShadowOpacityProperty, value);
}
#endregion
#region ShadowColor Dependency Property
public static readonly DependencyProperty ShadowColorProperty = DependencyProperty.Register(
nameof(ShadowColor),
typeof(Color),
typeof(InnerDropShadowPanel),
new PropertyMetadata(Colors.Transparent, OnShadowColorChanged));
public Color ShadowColor
{
get => (Color)GetValue(ShadowColorProperty);
set => SetValue(ShadowColorProperty, value);
}
private static void OnShadowColorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (o is InnerDropShadowPanel thisControl)
{
thisControl.UpdateShadowColor();
}
}
#endregion
#region BlurRadiusLeft Dependency Property
public static readonly DependencyProperty BlurRadiusLeftProperty = DependencyProperty.Register(
nameof(BlurRadiusLeft),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusLeft
{
get => (double)GetValue(BlurRadiusLeftProperty);
set => SetValue(BlurRadiusLeftProperty, value);
}
#endregion
#region BlurRadiusRight Dependency Property
public static readonly DependencyProperty BlurRadiusRightProperty = DependencyProperty.Register(
nameof(BlurRadiusRight),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusRight
{
get => (double)GetValue(BlurRadiusRightProperty);
set => SetValue(BlurRadiusRightProperty, value);
}
#endregion
#region BlurRadiusTop Dependency Property
public static readonly DependencyProperty BlurRadiusTopProperty = DependencyProperty.Register(
nameof(BlurRadiusTop),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusTop
{
get => (double)GetValue(BlurRadiusTopProperty);
set => SetValue(BlurRadiusTopProperty, value);
}
#endregion
#region BlurRadiusBottom Dependency Property
public static readonly DependencyProperty BlurRadiusBottomProperty = DependencyProperty.Register(
nameof(BlurRadiusBottom),
typeof(double),
typeof(InnerDropShadowPanel),
new PropertyMetadata(0d, OnPropertyChanged));
public double BlurRadiusBottom
{
get => (double)GetValue(BlurRadiusBottomProperty);
set => SetValue(BlurRadiusBottomProperty, value);
}
#endregion
}
}
以及控件模板:
<Style TargetType="local:InnerDropShadowPanel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:InnerDropShadowPanel">
<Grid>
<ContentPresenter/>
<Border x:Name="PART_LeftBorder"
Opacity="0.5"
HorizontalAlignment="Left"
VerticalAlignment="Stretch">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Black" Offset="0" x:Name="PART_LeftGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="PART_RightBorder"
Opacity="0.5"
HorizontalAlignment="Right"
VerticalAlignment="Stretch">
<Border.Background>
<LinearGradientBrush StartPoint="1,0" EndPoint="0,0">
<GradientStop Color="Black" Offset="0" x:Name="PART_RightGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="PART_TopBorder"
Opacity="0.5"
HorizontalAlignment="Stretch"
VerticalAlignment="Top">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Black" Offset="0" x:Name="PART_TopGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="PART_BottomBorder"
Opacity="0.5"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom">
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="Black" Offset="0" x:Name="PART_BottomGradient"/>
<GradientStop Color="Transparent" Offset="0.5"/>
</LinearGradientBrush>
</Border.Background></Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
与 XAML 像这样:
<local:InnerDropShadowPanel HorizontalAlignment="Center"
BlurRadiusLeft="6"
BlurRadiusTop="6"
ShadowOpacity="0.4"
ShadowColor="Black">
<TextBlock Text="Test"
Foreground="Black"
FontSize="120"
Margin="50,20"/>
</local:InnerDropShadowPanel>
你得到这样的结果:
您可以在任何一侧或全部添加阴影,并整体更改阴影的颜色和不透明度:
<local:InnerDropShadowPanel HorizontalAlignment="Center"
BlurRadiusLeft="6"
BlurRadiusTop="6"
BlurRadiusBottom="50"
BlurRadiusRight="100"
ShadowOpacity="1"
ShadowColor="Red">
<TextBlock Text="Test"
Foreground="Black"
FontSize="120"
Margin="50,20"/>
</local:InnerDropShadowPanel>
给你这个:
我相信您可以修改此控件并通过添加自定义设置来发挥作用,例如,每一面都有不同的颜色或不透明度。不过,上述解决方案可能足以满足绝大多数情况。