如何在WPF中的非透明用户控件上制作透明部分
How to make transparent part on non-transparent user control in WPF
在我的 MainWindow.xaml 上有用户控制图块,每个图块的背景设置如下:
ucTile.Background = new SolidColorBrush(Colors.Some);
取决于各种用户设置。
现在我想向我的应用程序添加一个新功能:可以为主 window 设置自定义背景图像。
但是我需要我的图块的某些部分是透明的,以显示它们下面的图像。 像这样:
这是我的瓷砖现在的样子:
如何实现?我不能将我的 ucTile 背景设置为透明,因为如果应该保留颜色。 是否有一些组件 inf WPF 可以充当 "hole" 显示非透明元素下的内容?
简单的解决方案:
<Window Background="Transparent">
<Polygon Fill="LightBlue"/>
</Window>
您需要添加 Points
以获得所需的形状!
阅读更多关于多边形的内容here!
这里有一些细节,因为有些人觉得无缘无故地否决是好的...
用户控件
<UserControl x:Class="WpfApp1.FolderControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Polygon Fill="Red"
Grid.RowSpan="2"
Points="0,0 , 50,0 , 55,10 , 100,10 , 100,80 , 0,80 " />
<Image Source="if_desktop_83651.png" Margin="5,20,5,5" Height="24" Width="24"></Image>
<Border Background="Green"
Grid.Row="1"
Margin="5">
<TextBlock Text="Caption"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"/>
</Border>
</Grid>
Window
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
Background="Green">
<local:FolderControl HorizontalAlignment="Center"
VerticalAlignment="Center"/>
结果
优点:
- 你可以做任何你想要的形状
缺点:
- 不会调整大小 -> 在代码
中计算 Points
您可以在其 ControlTemplate 中为 UserControl 的大纲设置一个 Path 元素。 Path 的 Fill
、Stroke
和 StrokeThickness
属性绑定到 UserControl 的 Background
、BorderBrush
和(新定义的)OutlineThickness
,因此您可以照常设置它们。
<UserControl x:Class="YourNamespace.Tile" ...>
<UserControl.Template>
<ControlTemplate TargetType="local:Tile">
<Grid>
<Path Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding BorderBrush}"
StrokeLineJoin="Round"
StrokeThickness="{TemplateBinding OutlineThickness}"
Data="{TemplateBinding Outline}"/>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</UserControl.Template>
<Grid>
...
</Grid>
</UserControl>
Path 绑定到 Tile 控件的两个依赖项 属性:
public partial class Tile : UserControl
{
public Tile()
{
InitializeComponent();
}
public static readonly DependencyProperty OutlineProperty =
DependencyProperty.Register(
nameof(Outline), typeof(Geometry), typeof(Tile));
public Geometry Outline
{
get { return (Geometry)GetValue(OutlineProperty); }
set { SetValue(OutlineProperty, value); }
}
public static readonly DependencyProperty OutlineThicknessProperty =
DependencyProperty.Register(
nameof(OutlineThickness), typeof(double), typeof(Tile),
new PropertyMetadata(1.0, (o, e) => ((Tile)o).UpdateOutline()));
public double OutlineThickness
{
get { return (double)GetValue(OutlineThicknessProperty); }
set { SetValue(OutlineThicknessProperty, value); }
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
UpdateOutline();
}
private void UpdateOutline()
{
var geometry = new StreamGeometry();
var size = RenderSize;
var border = OutlineThickness / 2d;
using (var sgc = geometry.Open())
{
sgc.BeginFigure(new Point(border, border), true, true);
sgc.LineTo(new Point(size.Width - 20, border), true, true);
sgc.LineTo(new Point(size.Width - border, 20), true, true);
sgc.LineTo(new Point(size.Width - border, size.Height - border), true, true);
sgc.LineTo(new Point(0, size.Height - border), true, true);
}
Outline = geometry;
}
}
现在根据需要扩展 UpdateOutline
方法。
如果 XAML 设计者抱怨 ControlTemplate 的 TargetType,你不妨使用这个:
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid>
<Path Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding BorderBrush}"
StrokeLineJoin="Round"
StrokeThickness="{Binding OutlineThickness, RelativeSource={RelativeSource TemplatedParent}}"
Data="{Binding Outline, RelativeSource={RelativeSource TemplatedParent}}"/>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</UserControl.Template>
在我的 MainWindow.xaml 上有用户控制图块,每个图块的背景设置如下:
ucTile.Background = new SolidColorBrush(Colors.Some);
取决于各种用户设置。
现在我想向我的应用程序添加一个新功能:可以为主 window 设置自定义背景图像。
但是我需要我的图块的某些部分是透明的,以显示它们下面的图像。 像这样:
这是我的瓷砖现在的样子:
如何实现?我不能将我的 ucTile 背景设置为透明,因为如果应该保留颜色。 是否有一些组件 inf WPF 可以充当 "hole" 显示非透明元素下的内容?
简单的解决方案:
<Window Background="Transparent">
<Polygon Fill="LightBlue"/>
</Window>
您需要添加 Points
以获得所需的形状!
阅读更多关于多边形的内容here!
这里有一些细节,因为有些人觉得无缘无故地否决是好的...
用户控件
<UserControl x:Class="WpfApp1.FolderControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Polygon Fill="Red"
Grid.RowSpan="2"
Points="0,0 , 50,0 , 55,10 , 100,10 , 100,80 , 0,80 " />
<Image Source="if_desktop_83651.png" Margin="5,20,5,5" Height="24" Width="24"></Image>
<Border Background="Green"
Grid.Row="1"
Margin="5">
<TextBlock Text="Caption"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"/>
</Border>
</Grid>
Window
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
Background="Green">
<local:FolderControl HorizontalAlignment="Center"
VerticalAlignment="Center"/>
结果
优点:
- 你可以做任何你想要的形状
缺点:
- 不会调整大小 -> 在代码 中计算
Points
您可以在其 ControlTemplate 中为 UserControl 的大纲设置一个 Path 元素。 Path 的 Fill
、Stroke
和 StrokeThickness
属性绑定到 UserControl 的 Background
、BorderBrush
和(新定义的)OutlineThickness
,因此您可以照常设置它们。
<UserControl x:Class="YourNamespace.Tile" ...>
<UserControl.Template>
<ControlTemplate TargetType="local:Tile">
<Grid>
<Path Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding BorderBrush}"
StrokeLineJoin="Round"
StrokeThickness="{TemplateBinding OutlineThickness}"
Data="{TemplateBinding Outline}"/>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</UserControl.Template>
<Grid>
...
</Grid>
</UserControl>
Path 绑定到 Tile 控件的两个依赖项 属性:
public partial class Tile : UserControl
{
public Tile()
{
InitializeComponent();
}
public static readonly DependencyProperty OutlineProperty =
DependencyProperty.Register(
nameof(Outline), typeof(Geometry), typeof(Tile));
public Geometry Outline
{
get { return (Geometry)GetValue(OutlineProperty); }
set { SetValue(OutlineProperty, value); }
}
public static readonly DependencyProperty OutlineThicknessProperty =
DependencyProperty.Register(
nameof(OutlineThickness), typeof(double), typeof(Tile),
new PropertyMetadata(1.0, (o, e) => ((Tile)o).UpdateOutline()));
public double OutlineThickness
{
get { return (double)GetValue(OutlineThicknessProperty); }
set { SetValue(OutlineThicknessProperty, value); }
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
UpdateOutline();
}
private void UpdateOutline()
{
var geometry = new StreamGeometry();
var size = RenderSize;
var border = OutlineThickness / 2d;
using (var sgc = geometry.Open())
{
sgc.BeginFigure(new Point(border, border), true, true);
sgc.LineTo(new Point(size.Width - 20, border), true, true);
sgc.LineTo(new Point(size.Width - border, 20), true, true);
sgc.LineTo(new Point(size.Width - border, size.Height - border), true, true);
sgc.LineTo(new Point(0, size.Height - border), true, true);
}
Outline = geometry;
}
}
现在根据需要扩展 UpdateOutline
方法。
如果 XAML 设计者抱怨 ControlTemplate 的 TargetType,你不妨使用这个:
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid>
<Path Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding BorderBrush}"
StrokeLineJoin="Round"
StrokeThickness="{Binding OutlineThickness, RelativeSource={RelativeSource TemplatedParent}}"
Data="{Binding Outline, RelativeSource={RelativeSource TemplatedParent}}"/>
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</UserControl.Template>