问题
I have a simple class derived from Button with a dependency property:
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));
}
I have the following style for the CircleButton:
<Style x:Key="CircleButtonStyle" TargetType="{x:Type controls1:CircleButton}">
...
<Setter Property="Content">
<Setter.Value>
<Rectangle Style="{StaticResource CircleButtonRectangleStyle}"/>
</Setter.Value>
</Setter>
...
</Style>
The rectangle style referenced in the CircleButton style is defined as:
<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>
Finally, my XAML defines three CircleButton instances:
<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>
All three buttons display, but only the last in the sequence has an image (it is the correct one). This occurs no matter how many buttons I add.
Anyone see what I'm missing and what I need to do to correct it?
回答1:
It's not obvious, but in fact you're only defining one instance of VisualBrush
. There will be exactly one copy of the content of that Setter.Value
element. Each time it gets added to one of your circle buttons, it gets yanked out of the previous one.
Try applying a template instead, and apply that visual brush to an element in the template. Elements in a template are created individually every time the template is applied.
Now, you can't apply a ControlTemplate
to a Rectangle
. But you can apply lots of templates to lots of things, so no big deal.
This might work. Button
is a subclass of ContentControl
so it's got a ContentTemplate
property, which is instantiated to display whatever you put in the Button
's Content
property. This use is a little funny because it doesn't display the Content
-- but you're not using 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>
But you know what type ContentControl.Content
is? It's Object
. You can stuff anything in there, and the ContentTemplate
can do whatever it likes with whatever it finds. I bet this would work just fine, and might save you having to write that CircleButton
subclass at all:
<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}"
/>
来源:https://stackoverflow.com/questions/36207572/wpf-accesses-only-single-instance-of-derived-class-with-dependency-property