通过绑定应用样式
Applying Styles With Binding
我正在尝试创建一个名为 PieceImage
的自定义控件,其中包含多个预定义 Canvas
元素之一。我在名为 PieceImageDictionary.xaml 的 ResourceDictionary
中定义了这些画布。我在 PieceImage
、Color1
和 Color2
中设置了一些依赖属性,我想将它们绑定到 Fill
和 Stroke
中的路径画布。我对自定义控件和简单的数据绑定有很好的理解,但样式让我有点困惑。
所以基本上我有一个 ResourceDictionary
和画布,我将其视为图像,我希望能够有多个 PieceImage
Control
实例,每个实例都可以选择这些图像之一独立(不是全局样式)并且我希望能够使用 PieceImage
控件上的 DependencyProperty
设置颜色。
我曾尝试将我的画布包装在 ControlTemplates
中,但出于某种原因“Canvas
”不是有效的 TargetType
。
如果我将 TargetType
设置为“Control
”,我就会应用此模板,但是当我尝试将 TemplateBinding
添加到 Paths
时,属性 我想设置 (Color1)
找不到。我有点理解这一点,因为 Color1
属性 在我的 PieceImage
控制中,所以 TemplateBinding
到 Control
甚至 Canvas
都不会没用。
然后我尝试 RelativeBinding
并使用 AncestorType
的“PieceImage
”,但这也不起作用。没有错误,只是一个空白 Canvas
。我试过在 Canvas
上调用 UpdateLayout()
和 InvalidateVisual()
以防万一,但没有改变。
我尝试使用 XamlReader
和 Writer 来创建这些画布,而不是使用模板,这最初在我静态定义颜色时有效,但当我尝试添加 RelativeBinding
时,我得到了 Xaml 解析错误说它无法从字符串“local:PieceImage
”
创建类型
我尝试在代码中添加绑定,但还是空白 Canvas
。我承认我不太了解编码绑定,这是我的实现:
var binding = new Binding(Color1Property.Name);
binding.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
BindingOperations.SetBinding(path, Path.FillProperty, binding);
这是我的基本代码,为了清楚起见,我已经清除了所有失败的尝试,否则它会变得一团糟。
PieceImage.cs
public class PieceImage : Control
{
private Canvas _canvas;
static PieceImage()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PieceImage), new FrameworkPropertyMetadata(typeof(PieceImage)));
}
public static readonly DependencyProperty Color1Property = DependencyProperty.Register(nameof(Color1), typeof(Brush), typeof(PieceImage), new PropertyMetadata(Brushes.BlanchedAlmond));
public static readonly DependencyProperty Color2Property = DependencyProperty.Register(nameof(Color2), typeof(Brush), typeof(PieceImage), new PropertyMetadata(Brushes.DarkGray));
public static readonly DependencyProperty PieceTypeProperty = DependencyProperty.Register(nameof(PieceType), typeof(Enums.PieceType), typeof(PieceImage), new PropertyMetadata(Enums.PieceType.Pawn));
public static readonly DependencyProperty SwapColorsProperty = DependencyProperty.Register(nameof(SwapColors), typeof(bool), typeof(PieceImage), new PropertyMetadata(false));
public Brush Color1
{
get { return (Brush)GetValue(Color1Property); }
set { SetValue(Color1Property, value); }
}
public Brush Color2
{
get { return (Brush)GetValue(Color2Property); }
set { SetValue(Color2Property, value); }
}
public Enums.PieceType PieceType
{
get { return (Enums.PieceType)GetValue(PieceTypeProperty); }
set { SetValue(PieceTypeProperty, value); }
}
public bool SwapColors
{
get { return (bool)GetValue(SwapColorsProperty); }
set { SetValue(SwapColorsProperty, value); }
}
public override void OnApplyTemplate()
{
_canvas = Template.FindName("PART_Canvas", this) as Canvas;
//Here is where most of my logic would go when I was loading xaml or coding bindings
base.OnApplyTemplate();
}
}
Generic.xaml(部分)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wagner.Chess.UI.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="\pieceimagedictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:PieceImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PieceImage">
<Canvas x:Name="PART_Canvas"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
PieceImageDictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wagner.Chess.UI.Controls">
<Canvas Height="64" Width="64" x:Key="BishopImage">
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color1}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeLineJoin="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38
C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.65,38.99
6.68,38.97 6,38 C 7.35,36.54 9,36 9,36 z"/>
<PathGeometry Figures="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5
22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z"/>
<PathGeometry Figures="M 25 8 A 2.5 2.5 0 1 1 20,8 A 2.5 2.5 0 1 1 25 8 z"/>
</GeometryGroup>
</Path.Data>
</Path>
<Path Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeLineJoin="Miter">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 17.5,26 L 27.5,26 M 15,30 L 30,30 M 22.5,15.5 L 22.5,20.5 M 20,18 L 25,18" />
</GeometryGroup>
</Path.Data>
</Path>
<Canvas.RenderTransform>
<ScaleTransform ScaleX="1.42222222222" ScaleY="1.42222222222"/>
</Canvas.RenderTransform>
</Canvas>
<Canvas Height="64" Width="64" x:Key="KnightImage">
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color1}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18"/>
<PathGeometry Figures="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,
30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L
18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10"/>
</GeometryGroup>
</Path.Data>
</Path>
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="0.5" StrokeMiterLimit="1" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z"/>
<PathGeometry Figures="M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z">
<PathGeometry.Transform>
<MatrixTransform Matrix="0.866,0.5,-0.5,0.866,9.693,-5.173"/>
</PathGeometry.Transform>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
<Canvas.RenderTransform>
<ScaleTransform ScaleX="1.42222222222" ScaleY="1.42222222222"/>
</Canvas.RenderTransform>
</Canvas>
</ResourceDictionary>
我希望有人可以提供一些提示或为我指明正确的方向,因为 MSDocs 有 StyleSelectors
和 DataTemplateSelectors
的指南,这两个指南更多地用于数据项样式而不是设置另一个变量使用样式进行控制。
谢谢,
如果我对您的问题的理解正确,您希望在 PieceImage
控件中显示基于 PieceType
的片段 Canvas
。然后,您不必将 Canvas
嵌套在另一个 Canvas
中。您可以将 PieceImage
模板中的 Canvas
替换为 ContentPresenter
(PART_ContentPresenter
).
<Style TargetType="{x:Type local:PieceImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PieceImage">
<ContentPresenter x:Name="PART_ContentPresenter"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在您的 PieceImage
控件中,您可以使用 FindResource
方法搜索相应的 PieceType
资源(Canvas
)并将其分配给 ContentPresenter
.这里我假设我们可以使用模式 <Enum Constant Name>Image
映射 PieceType
。如果它更复杂,您可以使用字典或自定义转换器。
public class PieceImage : Control
{
private ContentPresenter _contentPresenter;
// ...your constructor, dependency property definitions, etc..
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = Template.FindName("PART_ContentPresenter", this) as ContentPresenter;
if (_contentPresenter != null)
_contentPresenter.Content = FindPieceImage();
}
private Canvas FindPieceImage()
{
var pieceTypeName = PieceType.ToString();
var pieceTypeCanvasKey = $"{pieceTypeName}Image";
return FindResource(pieceTypeCanvasKey) as Canvas;
}
}
由于控件模板中原来的Canvas
没有了,请把你的作品图片中的所有和AncestorLevel=2
属性去掉,否则绑定源不会被发现。此外,将 x:Shared="False"
添加到您的 Canvas
es。这很重要,因为你的作品图像现在可能会被多次使用(我猜你正在构建一个棋盘),但没有将 x:Shared
设置为 false
相同的实例 将被重复使用。
When set to false
, modifies WPF resource-retrieval behavior so that requests for the attributed resource create a new instance for each request instead of sharing the same instance for all requests.
这是有问题的,因为每个控件只能有一个父元素。这意味着当您多次分配相同的 Canvas
实例时,只有最后一个元素会将其作为子元素。您可以想象一个棋盘,其中只显示最后被分配的棋子,棋盘的其余部分是空的。这是对您的代码所做修改的摘录。
<Canvas Height="64" Width="64" x:Key="BishopImage" x:Shared="False">
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,Mode=FindAncestor},Path=Color1}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeLineJoin="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38
C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.65,38.99
6.68,38.97 6,38 C 7.35,36.54 9,36 9,36 z"/>
<PathGeometry Figures="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5
22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z"/>
<PathGeometry Figures="M 25 8 A 2.5 2.5 0 1 1 20,8 A 2.5 2.5 0 1 1 25 8 z"/>
</GeometryGroup>
</Path.Data>
</Path>
<!-- ...other markup code. -->
绑定现在可以工作并解析为 PieceImage
,无需任何额外的代码或标记。
我正在尝试创建一个名为 PieceImage
的自定义控件,其中包含多个预定义 Canvas
元素之一。我在名为 PieceImageDictionary.xaml 的 ResourceDictionary
中定义了这些画布。我在 PieceImage
、Color1
和 Color2
中设置了一些依赖属性,我想将它们绑定到 Fill
和 Stroke
中的路径画布。我对自定义控件和简单的数据绑定有很好的理解,但样式让我有点困惑。
所以基本上我有一个 ResourceDictionary
和画布,我将其视为图像,我希望能够有多个 PieceImage
Control
实例,每个实例都可以选择这些图像之一独立(不是全局样式)并且我希望能够使用 PieceImage
控件上的 DependencyProperty
设置颜色。
我曾尝试将我的画布包装在 ControlTemplates
中,但出于某种原因“Canvas
”不是有效的 TargetType
。
如果我将 TargetType
设置为“Control
”,我就会应用此模板,但是当我尝试将 TemplateBinding
添加到 Paths
时,属性 我想设置 (Color1)
找不到。我有点理解这一点,因为 Color1
属性 在我的 PieceImage
控制中,所以 TemplateBinding
到 Control
甚至 Canvas
都不会没用。
然后我尝试 RelativeBinding
并使用 AncestorType
的“PieceImage
”,但这也不起作用。没有错误,只是一个空白 Canvas
。我试过在 Canvas
上调用 UpdateLayout()
和 InvalidateVisual()
以防万一,但没有改变。
我尝试使用 XamlReader
和 Writer 来创建这些画布,而不是使用模板,这最初在我静态定义颜色时有效,但当我尝试添加 RelativeBinding
时,我得到了 Xaml 解析错误说它无法从字符串“local:PieceImage
”
我尝试在代码中添加绑定,但还是空白 Canvas
。我承认我不太了解编码绑定,这是我的实现:
var binding = new Binding(Color1Property.Name);
binding.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
BindingOperations.SetBinding(path, Path.FillProperty, binding);
这是我的基本代码,为了清楚起见,我已经清除了所有失败的尝试,否则它会变得一团糟。
PieceImage.cs
public class PieceImage : Control
{
private Canvas _canvas;
static PieceImage()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PieceImage), new FrameworkPropertyMetadata(typeof(PieceImage)));
}
public static readonly DependencyProperty Color1Property = DependencyProperty.Register(nameof(Color1), typeof(Brush), typeof(PieceImage), new PropertyMetadata(Brushes.BlanchedAlmond));
public static readonly DependencyProperty Color2Property = DependencyProperty.Register(nameof(Color2), typeof(Brush), typeof(PieceImage), new PropertyMetadata(Brushes.DarkGray));
public static readonly DependencyProperty PieceTypeProperty = DependencyProperty.Register(nameof(PieceType), typeof(Enums.PieceType), typeof(PieceImage), new PropertyMetadata(Enums.PieceType.Pawn));
public static readonly DependencyProperty SwapColorsProperty = DependencyProperty.Register(nameof(SwapColors), typeof(bool), typeof(PieceImage), new PropertyMetadata(false));
public Brush Color1
{
get { return (Brush)GetValue(Color1Property); }
set { SetValue(Color1Property, value); }
}
public Brush Color2
{
get { return (Brush)GetValue(Color2Property); }
set { SetValue(Color2Property, value); }
}
public Enums.PieceType PieceType
{
get { return (Enums.PieceType)GetValue(PieceTypeProperty); }
set { SetValue(PieceTypeProperty, value); }
}
public bool SwapColors
{
get { return (bool)GetValue(SwapColorsProperty); }
set { SetValue(SwapColorsProperty, value); }
}
public override void OnApplyTemplate()
{
_canvas = Template.FindName("PART_Canvas", this) as Canvas;
//Here is where most of my logic would go when I was loading xaml or coding bindings
base.OnApplyTemplate();
}
}
Generic.xaml(部分)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wagner.Chess.UI.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="\pieceimagedictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:PieceImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PieceImage">
<Canvas x:Name="PART_Canvas"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
PieceImageDictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wagner.Chess.UI.Controls">
<Canvas Height="64" Width="64" x:Key="BishopImage">
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color1}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeLineJoin="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38
C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.65,38.99
6.68,38.97 6,38 C 7.35,36.54 9,36 9,36 z"/>
<PathGeometry Figures="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5
22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z"/>
<PathGeometry Figures="M 25 8 A 2.5 2.5 0 1 1 20,8 A 2.5 2.5 0 1 1 25 8 z"/>
</GeometryGroup>
</Path.Data>
</Path>
<Path Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeLineJoin="Miter">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 17.5,26 L 27.5,26 M 15,30 L 30,30 M 22.5,15.5 L 22.5,20.5 M 20,18 L 25,18" />
</GeometryGroup>
</Path.Data>
</Path>
<Canvas.RenderTransform>
<ScaleTransform ScaleX="1.42222222222" ScaleY="1.42222222222"/>
</Canvas.RenderTransform>
</Canvas>
<Canvas Height="64" Width="64" x:Key="KnightImage">
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color1}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 22,10 C 32.5,11 38.5,18 38,39 L 15,39 C 15,30 25,32.5 23,18"/>
<PathGeometry Figures="M 24,18 C 24.38,20.91 18.45,25.37 16,27 C 13,29 13.18,31.34 11,31 C 9.958,30.06 12.41,27.96 11,28 C 10,28 11.19,29.23 10,
30 C 9,30 5.997,31 6,26 C 6,24 12,14 12,14 C 12,14 13.89,12.1 14,10.5 C 13.27,9.506 13.5,8.5 13.5,7.5 C 14.5,6.5 16.5,10 16.5,10 L
18.5,10 C 18.5,10 19.28,8.008 21,7 C 22,7 22,10 22,10"/>
</GeometryGroup>
</Path.Data>
</Path>
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,AncestorLevel=2,Mode=FindAncestor},Path=Color2}"
StrokeThickness="0.5" StrokeMiterLimit="1" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 9.5 25.5 A 0.5 0.5 0 1 1 8.5,25.5 A 0.5 0.5 0 1 1 9.5 25.5 z"/>
<PathGeometry Figures="M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z">
<PathGeometry.Transform>
<MatrixTransform Matrix="0.866,0.5,-0.5,0.866,9.693,-5.173"/>
</PathGeometry.Transform>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
<Canvas.RenderTransform>
<ScaleTransform ScaleX="1.42222222222" ScaleY="1.42222222222"/>
</Canvas.RenderTransform>
</Canvas>
</ResourceDictionary>
我希望有人可以提供一些提示或为我指明正确的方向,因为 MSDocs 有 StyleSelectors
和 DataTemplateSelectors
的指南,这两个指南更多地用于数据项样式而不是设置另一个变量使用样式进行控制。
谢谢,
如果我对您的问题的理解正确,您希望在 PieceImage
控件中显示基于 PieceType
的片段 Canvas
。然后,您不必将 Canvas
嵌套在另一个 Canvas
中。您可以将 PieceImage
模板中的 Canvas
替换为 ContentPresenter
(PART_ContentPresenter
).
<Style TargetType="{x:Type local:PieceImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:PieceImage">
<ContentPresenter x:Name="PART_ContentPresenter"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在您的 PieceImage
控件中,您可以使用 FindResource
方法搜索相应的 PieceType
资源(Canvas
)并将其分配给 ContentPresenter
.这里我假设我们可以使用模式 <Enum Constant Name>Image
映射 PieceType
。如果它更复杂,您可以使用字典或自定义转换器。
public class PieceImage : Control
{
private ContentPresenter _contentPresenter;
// ...your constructor, dependency property definitions, etc..
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = Template.FindName("PART_ContentPresenter", this) as ContentPresenter;
if (_contentPresenter != null)
_contentPresenter.Content = FindPieceImage();
}
private Canvas FindPieceImage()
{
var pieceTypeName = PieceType.ToString();
var pieceTypeCanvasKey = $"{pieceTypeName}Image";
return FindResource(pieceTypeCanvasKey) as Canvas;
}
}
由于控件模板中原来的Canvas
没有了,请把你的作品图片中的所有和AncestorLevel=2
属性去掉,否则绑定源不会被发现。此外,将 x:Shared="False"
添加到您的 Canvas
es。这很重要,因为你的作品图像现在可能会被多次使用(我猜你正在构建一个棋盘),但没有将 x:Shared
设置为 false
相同的实例 将被重复使用。
When set to
false
, modifies WPF resource-retrieval behavior so that requests for the attributed resource create a new instance for each request instead of sharing the same instance for all requests.
这是有问题的,因为每个控件只能有一个父元素。这意味着当您多次分配相同的 Canvas
实例时,只有最后一个元素会将其作为子元素。您可以想象一个棋盘,其中只显示最后被分配的棋子,棋盘的其余部分是空的。这是对您的代码所做修改的摘录。
<Canvas Height="64" Width="64" x:Key="BishopImage" x:Shared="False">
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,Mode=FindAncestor},Path=Color1}"
Stroke="{Binding RelativeSource={RelativeSource AncestorType=local:PieceImage,Mode=FindAncestor},Path=Color2}"
StrokeThickness="1.5" StrokeMiterLimit="1" StrokeLineJoin="Round">
<Path.Data>
<GeometryGroup>
<PathGeometry Figures="M 9,36 C 12.39,35.03 19.11,36.43 22.5,34 C 25.89,36.43 32.61,35.03 36,36 C 36,36 37.65,36.54 39,38
C 38.32,38.97 37.35,38.99 36,38.5 C 32.61,37.53 25.89,38.96 22.5,37.5 C 19.11,38.96 12.39,37.53 9,38.5 C 7.65,38.99
6.68,38.97 6,38 C 7.35,36.54 9,36 9,36 z"/>
<PathGeometry Figures="M 15,32 C 17.5,34.5 27.5,34.5 30,32 C 30.5,30.5 30,30 30,30 C 30,27.5 27.5,26 27.5,26 C 33,24.5 33.5,14.5
22.5,10.5 C 11.5,14.5 12,24.5 17.5,26 C 17.5,26 15,27.5 15,30 C 15,30 14.5,30.5 15,32 z"/>
<PathGeometry Figures="M 25 8 A 2.5 2.5 0 1 1 20,8 A 2.5 2.5 0 1 1 25 8 z"/>
</GeometryGroup>
</Path.Data>
</Path>
<!-- ...other markup code. -->
绑定现在可以工作并解析为 PieceImage
,无需任何额外的代码或标记。