我正在尝试在WPF中创建一个用户控件,允许用户选择鞋子的特定区域(鞋跟,边缘,鞋底等)
这个想法是你有一个鞋子的图像(图纸),你可以点击各个部分并选择区域。
我正在使用一组模板化的复选框。
有一个复选框,其中包含一个定义边的路径,然后是一组定义各个区域的矩形。
这很有效,但显然它看起来并不好看。为了让它看起来更好,我想要隐藏不在原始鞋道内的所有东西。
矩形全部位于网格中的单独行中,背景鞋跨越所有行。
我尝试将父网格的Clip属性设置为与背景鞋边相同的路径,但得到了一些奇怪的结果:
我很确定我的网格剪辑是正确的,但我不明白这里发生了什么。
如果有人可以帮助解决这个问题或建议更好的方法来完成同样的任务,我将不胜感激。
<Geometry x:Key="ShoeEdgeGeometry">M26.25,0.5 C40.471332,0.5 52,17.625107 52,38.75 52,51.292905 47.935695,62.425729 41.656635,69.401079 L41.349452,69.733874 42.012107,70.457698 C45.421829,74.364614 47.5,79.554564 47.5,85.25 47.5,97.400265 38.042015,107.25 26.375,107.25 14.707984,107.25 5.2499995,97.400265 5.2499991,85.25 5.2499995,79.554564 7.3281701,74.364614 10.737891,70.457698 L11.276058,69.869853 10.843364,69.401079 C4.5643053,62.425729 0.49999952,51.292905 0.5,38.75 0.49999952,17.625107 12.028667,0.5 26.25,0.5 z</Geometry>
<Grid Margin="0"
Clip="{StaticResource ShoeEdgeGeometry}">
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="4*" />
<RowDefinition Height="2*" />
<RowDefinition Height="2*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<!-- The edge check box-->
<CheckBox x:Name="ShoeEdgeRegion"
Grid.Row="0"
Grid.RowSpan="5">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Path x:Name="MainPath"
Data="{StaticResource ShoeEdgeGeometry}"
Fill="{StaticResource TransparentBrush}"
Stroke="Black"
Stretch="Fill" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Toe check box-->
<CheckBox x:Name="ShoeToeRegion"
Grid.Row="0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Sole check box-->
<CheckBox x:Name="ShoeSoleRegion"
Grid.Row="1"
Margin="0,-1,0,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Instep check box-->
<CheckBox x:Name="ShoeInstepRegion"
Margin="0,-1,0,0"
Grid.Row="2">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Lower heel check box-->
<CheckBox x:Name="ShoeLowerHeelRegion"
Grid.Row="3"
Margin="0,-1,0,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The heel check box-->
<CheckBox x:Name="ShoeHeelRegion"
Grid.Row="4"
Margin="0,-1,0,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid>
答案 0 :(得分:13)
根据您提供的代码,我已经复制了您描述的问题。我们假设网格的大小 100x200 。首先,这里是网格看起来如何没有和剪辑集:
显然结果是一样的。但是,如果我们在网格中添加一些背景(红色是网格的背景,蓝色是网格背后的背景),它的外观如下:
现在我们可以清楚地看到这里发生了什么 - 几何体(大致 50x100 )没有自动缩放到网格的大小,而是维持原始大小,从而剪切整批更多我们想要的。如果我们调整网格大小以匹配几何体的大小,它就是这样的:
为了使我们的工作更轻松,我已将几何图形定义提取到资源并对其进行标准化,使其大小 1x1 ,这将使缩放更容易。以下是资源:
<PathFigureCollection x:Key="ShoeEdgeFigures">
M 0.5048,0
C 0.7783,0 1,0.164 1,0.361 1,0.478 0.9218,0.582 0.8011,0.647
L 0.7952,0.65 0.8079,0.657
C 0.8735,0.693 0.9135,0.742 0.9135,0.795 0.9135,0.908 0.7316,1 0.5072,1
0.2828,1 0.101,0.908 0.101,0.795 0.101,0.742 0.1409,0.693 0.2065,0.657
L 0.2168,0.651 0.2085,0.647
C 0.0878,0.582 0,0.478 0,0.361 0,0.164 0.2313,0 0.5048,0
Z
</PathFigureCollection>
<PathGeometry x:Key="ShoeEdgeGeometry" Figures="{StaticResource ShoeEdgeFigures}" />
为了使网格看起来像我们期望的那样我们需要缩放几何体 - 这可以通过Geometry.Transform
属性来完成。我认为为此目的定义新几何图形是有益的。然后,我们只需要在几何图形上设置ScaleTransform
,ScaleX
和ScaleY
分别等于网格的宽度和高度。那是因为几何体的初始尺寸 1x1 。这是代码:
<Grid Width="100" Height="200" (...)>
<Grid.Resources>
<PathGeometry x:Key="StaticClipGeometry" Figures="{StaticResource ShoeEdgeFigures}">
<PathGeometry.Transform>
<ScaleTransform ScaleX="100" ScaleY="200" />
</PathGeometry.Transform>
</PathGeometry>
</Grid.Resources>
<Grid.Clip>
<StaticResource ResourceKey="StaticClipGeometry" />
</Grid.Clip>
(...)
</Grid>
但这有点限制,因为网格的大小需要保持不变并且在编译时是已知的。
要使剪辑几何体动态调整到网格的大小,我们需要绑定Geometry.Transform
属性,因为我们将绑定到Grid.ActualWidth
和Grid.ActualHeight
,我们将需要一个简单的转换器:
public class SizeToScaleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return new ScaleTransform
{
ScaleX = (double)values[0],
ScaleY = (double)values[1],
};
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
然后我们定义网格:
<Grid (...)>
<Grid.Resources>
<PathGeometry x:Key="DynamicClipGeometry" Figures="{StaticResource ShoeEdgeFigures}">
<PathGeometry.Transform>
<MultiBinding>
<MultiBinding.Converter>
<local:SizeToScaleConverter />
</MultiBinding.Converter>
<Binding RelativeSource="{RelativeSource AncestorType=Grid}"
Path="ActualWidth" />
<Binding RelativeSource="{RelativeSource AncestorType=Grid}"
Path="ActualHeight" />
</MultiBinding>
</PathGeometry.Transform>
</PathGeometry>
</Grid.Resources>
<Grid.Clip>
<StaticResource ResourceKey="DynamicClipGeometry" />
</Grid.Clip>
(...)
</Grid>
最终结果如下:
答案 1 :(得分:6)
您的路径的维度似乎非常不合适,但作为一种可接受的解决方法,我建议您使用Grid
将ViewBox
包围起来。
完整代码
<Window.Resources>
<Geometry x:Key="ShoeEdgeGeometry" >
M26.25,0.5 C40.471332,0.5 52,17.625107 52,38.75 52,51.292905 47.935695,62.425729 41.656635,69.401079 L41.349452,69.733874 42.012107,70.457698 C45.421829,74.364614 47.5,79.554564 47.5,85.25 47.5,97.400265 38.042015,107.25 26.375,107.25 14.707984,107.25 5.2499995,97.400265 5.2499991,85.25 5.2499995,79.554564 7.3281701,74.364614 10.737891,70.457698 L11.276058,69.869853 10.843364,69.401079 C4.5643053,62.425729 0.49999952,51.292905 0.5,38.75 0.49999952,17.625107 12.028667,0.5 26.25,0.5 z
</Geometry>
<SolidColorBrush x:Key="RedBrush" Color="Red"></SolidColorBrush>
<SolidColorBrush x:Key="TransparentBrush" Color="Transparent"></SolidColorBrush>
</Window.Resources>
<Viewbox Stretch="Fill">
<Grid Margin="0" Clip="{StaticResource ShoeEdgeGeometry}" >
<Grid.RowDefinitions>
<RowDefinition Height="0.2*" />
<RowDefinition Height="0.4*" />
<RowDefinition Height="0.2*" />
<RowDefinition Height="0.2*" />
<RowDefinition Height="0.2*" />
</Grid.RowDefinitions>
<!-- The edge check box-->
<CheckBox x:Name="ShoeEdgeRegion" Grid.Row="0" Grid.RowSpan="5">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Path x:Name="MainPath"
Data="{StaticResource ShoeEdgeGeometry}"
Fill="{StaticResource TransparentBrush}"
Stroke="Black"
Stretch="Fill" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Toe check box-->
<CheckBox x:Name="ShoeToeRegion"
Grid.Row="0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Sole check box-->
<CheckBox x:Name="ShoeSoleRegion"
Grid.Row="1"
Margin="0,-1,0,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Instep check box-->
<CheckBox x:Name="ShoeInstepRegion"
Margin="0,-1,0,0"
Grid.Row="2">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The Lower heel check box-->
<CheckBox x:Name="ShoeLowerHeelRegion"
Grid.Row="3"
Margin="0,-1,0,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
<!-- The heel check box-->
<CheckBox x:Name="ShoeHeelRegion"
Grid.Row="4"
Margin="0,-1,0,0">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Cursor"
Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Rectangle x:Name="MainPath"
StrokeThickness="1"
Fill="{StaticResource TransparentBrush}"
Stroke="Black" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Stroke"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsChecked"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MainPath"
Property="Fill"
Value="{StaticResource RedBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid>
</Viewbox>
<强>结果强>
希望这对你有用