WPF 仅访问具有依赖项 属性 的派生 class 的单个实例
WPF accesses only single instance of derived class with dependency property
我有一个简单的 class 派生自具有依赖关系的 Button 属性:
public sealed class CircleButton : Button
{
public Visual Visual
{
get { return (Visual)GetValue(VisualProperty); }
set { SetValue(VisualProperty, value); }
}
public static readonly DependencyProperty VisualProperty = DependencyProperty.Register("Visual", typeof(Visual), typeof(CircleButton));
}
CircleButton 的样式如下:
<Style x:Key="CircleButtonStyle" TargetType="{x:Type controls1:CircleButton}">
...
<Setter Property="Content">
<Setter.Value>
<Rectangle Style="{StaticResource CircleButtonRectangleStyle}"/>
</Setter.Value>
</Setter>
...
</Style>
CircleButton样式中引用的矩形样式定义为:
<Style x:Key="CircleButtonRectangleStyle" TargetType="{x:Type Rectangle}">
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Width, Converter={StaticResource ArithmeticConverter}}"/>
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Height, Converter={StaticResource ArithmeticConverter}}"/>
<Setter Property="Fill" Value="White"/>
<Setter Property="OpacityMask">
<Setter.Value>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Visual}"/>
</Setter.Value>
</Setter>
</Style>
最后,我的 XAML 定义了三个 CircleButton 实例:
<StackPanel Grid.Row="1" Grid.Column="2">
<controls:CircleButton HorizontalAlignment="Center" VerticalAlignment="Center" Width="30.0" Height="30.0"
Style="{DynamicResource CircleButtonStyle}" Command="{Binding Add}" ToolTip="Add new product filter." BorderBrush="White" BorderThickness="1"
Background="{DynamicResource AccentColorBrush}" Visual="{DynamicResource appbar_add}"/>
<controls:CircleButton HorizontalAlignment="Center" VerticalAlignment="Center" Width="30.0" Height="30.0"
Style="{DynamicResource CircleButtonStyle}" Command="{Binding Remove}" ToolTip="Remove product filter." BorderBrush="White" BorderThickness="1"
Background="{DynamicResource AccentColorBrush}" Visual="{DynamicResource appbar_minus}"/>
<controls:CircleButton HorizontalAlignment="Center" VerticalAlignment="Center" Width="30.0" Height="30.0"
Style="{DynamicResource CircleButtonStyle}" Command="{Binding Remove}" ToolTip="Remove product filter." BorderBrush="White" BorderThickness="1"
Background="{DynamicResource AccentColorBrush}" Visual="{DynamicResource appbar_music}"/>
</StackPanel>
显示所有三个按钮,但序列中只有最后一个有图像(它是正确的)。无论我添加多少按钮,都会发生这种情况。
有人看到我遗漏了什么以及我需要做些什么来纠正它吗?
这并不明显,但实际上您只是定义了 VisualBrush
的一个实例。该 Setter.Value
元素的内容将只有一个副本。每次它被添加到你的一个圆圈按钮时,它就会从前一个按钮中拉出来。
尝试应用模板,并将视觉画笔应用到模板中的元素。每次应用模板时,模板 中的元素都是单独创建的 。
现在,您无法将 ControlTemplate
应用于 Rectangle
。但是您可以将很多模板应用于很多事情,所以没什么大不了的。
这可能有效。 Button
是 ContentControl
的子类,因此它有一个 ContentTemplate
属性,它被实例化以显示您放入 Button
的 Content
中的任何内容] 属性。这种用法有点滑稽,因为它不显示 Content
——但您没有使用 Content
。
<Style x:Key="CircleButtonStyle" TargetType="{x:Type controls1:CircleButton}">
<!-- ... -->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Width, Converter={StaticResource ArithmeticConverter}}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Height, Converter={StaticResource ArithmeticConverter}}"
Fill="White"
>
<Rectangle.OpacityMask>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Visual}"/>
</Rectangle.OpacityMask>
</Rectangle>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
但是你知道ContentControl.Content
是什么类型吗?是 Object
。你可以在里面塞任何东西,ContentTemplate
可以随心所欲地处理它找到的任何东西。我敢打赌这会工作得很好,并且可能会让你不必编写 CircleButton
子类:
<Style x:Key="CircleButtonStyle" TargetType="{x:Type Button}">
<!-- ... -->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Width, Converter={StaticResource ArithmeticConverter}}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Height, Converter={StaticResource ArithmeticConverter}}"
Fill="White"
>
<Rectangle.OpacityMask>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Content}"/>
</Rectangle.OpacityMask>
</Rectangle>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ... -->
<Button
Style="{DynamicResource CircleButtonStyle}"
Command="{Binding Remove}"
ToolTip="Remove product filter."
Content="{DynamicResource appbar_music}"
/>
我有一个简单的 class 派生自具有依赖关系的 Button 属性:
public sealed class CircleButton : Button
{
public Visual Visual
{
get { return (Visual)GetValue(VisualProperty); }
set { SetValue(VisualProperty, value); }
}
public static readonly DependencyProperty VisualProperty = DependencyProperty.Register("Visual", typeof(Visual), typeof(CircleButton));
}
CircleButton 的样式如下:
<Style x:Key="CircleButtonStyle" TargetType="{x:Type controls1:CircleButton}">
...
<Setter Property="Content">
<Setter.Value>
<Rectangle Style="{StaticResource CircleButtonRectangleStyle}"/>
</Setter.Value>
</Setter>
...
</Style>
CircleButton样式中引用的矩形样式定义为:
<Style x:Key="CircleButtonRectangleStyle" TargetType="{x:Type Rectangle}">
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Width, Converter={StaticResource ArithmeticConverter}}"/>
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Height, Converter={StaticResource ArithmeticConverter}}"/>
<Setter Property="Fill" Value="White"/>
<Setter Property="OpacityMask">
<Setter.Value>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Visual}"/>
</Setter.Value>
</Setter>
</Style>
最后,我的 XAML 定义了三个 CircleButton 实例:
<StackPanel Grid.Row="1" Grid.Column="2">
<controls:CircleButton HorizontalAlignment="Center" VerticalAlignment="Center" Width="30.0" Height="30.0"
Style="{DynamicResource CircleButtonStyle}" Command="{Binding Add}" ToolTip="Add new product filter." BorderBrush="White" BorderThickness="1"
Background="{DynamicResource AccentColorBrush}" Visual="{DynamicResource appbar_add}"/>
<controls:CircleButton HorizontalAlignment="Center" VerticalAlignment="Center" Width="30.0" Height="30.0"
Style="{DynamicResource CircleButtonStyle}" Command="{Binding Remove}" ToolTip="Remove product filter." BorderBrush="White" BorderThickness="1"
Background="{DynamicResource AccentColorBrush}" Visual="{DynamicResource appbar_minus}"/>
<controls:CircleButton HorizontalAlignment="Center" VerticalAlignment="Center" Width="30.0" Height="30.0"
Style="{DynamicResource CircleButtonStyle}" Command="{Binding Remove}" ToolTip="Remove product filter." BorderBrush="White" BorderThickness="1"
Background="{DynamicResource AccentColorBrush}" Visual="{DynamicResource appbar_music}"/>
</StackPanel>
显示所有三个按钮,但序列中只有最后一个有图像(它是正确的)。无论我添加多少按钮,都会发生这种情况。
有人看到我遗漏了什么以及我需要做些什么来纠正它吗?
这并不明显,但实际上您只是定义了 VisualBrush
的一个实例。该 Setter.Value
元素的内容将只有一个副本。每次它被添加到你的一个圆圈按钮时,它就会从前一个按钮中拉出来。
尝试应用模板,并将视觉画笔应用到模板中的元素。每次应用模板时,模板 中的元素都是单独创建的 。
现在,您无法将 ControlTemplate
应用于 Rectangle
。但是您可以将很多模板应用于很多事情,所以没什么大不了的。
这可能有效。 Button
是 ContentControl
的子类,因此它有一个 ContentTemplate
属性,它被实例化以显示您放入 Button
的 Content
中的任何内容] 属性。这种用法有点滑稽,因为它不显示 Content
——但您没有使用 Content
。
<Style x:Key="CircleButtonStyle" TargetType="{x:Type controls1:CircleButton}">
<!-- ... -->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Width, Converter={StaticResource ArithmeticConverter}}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Height, Converter={StaticResource ArithmeticConverter}}"
Fill="White"
>
<Rectangle.OpacityMask>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls1:CircleButton}}, Path=Visual}"/>
</Rectangle.OpacityMask>
</Rectangle>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
但是你知道ContentControl.Content
是什么类型吗?是 Object
。你可以在里面塞任何东西,ContentTemplate
可以随心所欲地处理它找到的任何东西。我敢打赌这会工作得很好,并且可能会让你不必编写 CircleButton
子类:
<Style x:Key="CircleButtonStyle" TargetType="{x:Type Button}">
<!-- ... -->
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Width, Converter={StaticResource ArithmeticConverter}}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Height, Converter={StaticResource ArithmeticConverter}}"
Fill="White"
>
<Rectangle.OpacityMask>
<VisualBrush Visual="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}, Path=Content}"/>
</Rectangle.OpacityMask>
</Rectangle>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ... -->
<Button
Style="{DynamicResource CircleButtonStyle}"
Command="{Binding Remove}"
ToolTip="Remove product filter."
Content="{DynamicResource appbar_music}"
/>