我把这个问题分解成一个更简单的形式,但我仍然想不出来。我有一个空白的WPF应用程序,在主XAML文件中只有一个按钮。
按钮有2个图标,根据窗口的状态而改变。图标的画笔属性绑定到按钮的前景属性,该属性在窗口处于活动状态或非活动状态时发生变化。一切都很好,直到我最大化窗口,但第二个图标没有显示。我知道最大化窗口状态正在工作,因为我能够将按钮的背景更改为蓝色。
我得到一个绑定失败错误"Cannot find source: RelativeSource FindAncestor, AncestorType='System.Windows.Controls '。按钮",AncestorLevel = ' 1 ' !">
我对默认状态使用了相同的绑定,它可以正常工作。它只在第二个图标的数据触发器内部无法更新。
显示问题的快照&误差
<Button Width="32" Height="32" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button.Style>
<Style TargetType="{x:Type Button}">
<!--Default-->
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Content">
<Setter.Value>
<Viewbox Width="16" Height="16" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}" Geometry="F1M12,12L4,12 4,4 12,4z M3,13L13,13 13,3 3,3z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</Setter.Value>
</Setter>
<Style.Triggers>
<!--Window inactive-->
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Value="false">
<Setter Property="Foreground" Value="White"/>
</DataTrigger>
<!--Window maximized-->
<DataTrigger Binding="{Binding Path=WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Value="Maximized">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Content">
<Setter.Value>
<Viewbox Width="16" Height="16" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#00FFFFFF" Geometry="F1M16,16L0,16 0,0 16,0z" />
<GeometryDrawing Brush="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}" Geometry="F1M11.999,10.002L10.998,10.002 10.998,5.002 5.998,5.002 5.998,4.001 11.999,4.001z M10.002,11.999L4.001,11.999 4.001,5.998 10.002,5.998z M5.002,3L5.002,5.002 3,5.002 3,13 10.998,13 10.998,10.998 13,10.998 13,3z" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Viewbox>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
谢谢大家的帮助!下面的两个答案都是完美的。我也看了一下Sergey提出的类似问题:
WPF Style中的数据触发器:Change content不起作用
通过将图标的路径内容放在Resources
中并使用DataTrigger
中的路径内容也可以工作。但是,使用这种方法,图标不会显示在设计器中,因此我更喜欢注释中的其他两种方法。
我已经标记谢尔盖的回答作为公认的答案作为RelativeSource Binding FindAncestor Mode
的解释,我错了的地方是非常有用的。
再次感谢大家!
如何使用'ControlTemplate'而不是改变'Content'本身在DataTrigger?
这是一个例子。
<Button>
<Button.Resources>
<DataTemplate x:Key="DEFAULT">
<Border Background="#DDDDDD"
BorderBrush="#AA111111"
BorderThickness="1">
<Viewbox Width="16" Height="16">
<Canvas Width="16" Height="16">
<Path Data="F1M16,16L0,16 0,0 16,0z" Fill="#00FFFFFF"/>
<Path Data="F1M12,12L4,12 4,4 12,4z M3,13L13,13 13,3 3,3z"
Fill="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}}, Path=Foreground}"/>
</Canvas>
</Viewbox>
</Border>
</DataTemplate>
<DataTemplate x:Key="MAX">
<Border Background="Blue"
BorderBrush="#AA111111"
BorderThickness="1">
<Viewbox Width="16" Height="16">
<Canvas Width="16" Height="16">
<Path Data="F1M16,16L0,16 0,0 16,0z" Fill="#00FFFFFF"/>
<Path Data="F1M11.999,10.002L10.998,10.002 10.998,5.002 5.998,5.002 5.998,4.001 11.999,4.001z M10.002,11.999L4.001,11.999 4.001,5.998 10.002,5.998z M5.002,3L5.002,5.002 3,5.002 3,13 10.998,13 10.998,10.998 13,10.998 13,3z"
Fill="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}}, Path=Foreground}"/>
</Canvas>
</Viewbox>
</Border>
</DataTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="32"/>
<Setter Property="Height" Value="32"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="ContentTemplate" Value="{StaticResource DEFAULT}"/>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter/>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=IsActive}" Value="False">
<Setter Property="Foreground" Value="#FFFFFF"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=WindowState}" Value="Maximized">
<Setter Property="ContentTemplate" Value="{StaticResource MAX}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Resources>
</Button>
建议您定义ControlTemplate并使用ControlTemplate中的Trigger来更改内容。
您误解了RelativeSource Binding FindAncestor Mode
的工作原理。NOT以这样一种方式工作,即在任何给定时间将属性绑定到所需类型的最近祖先。在创建绑定时,只会发现一次祖先。在您的示例中,在DataTrigger
setter中创建的Viewbox
在创建时没有按钮类型祖先(因为它还不是可视树的一部分)。因此,这个绑定在初始化时给出一个错误。
可能的解决方案是使用DataTemplate
,如elena.kim所建议的或ControlTemplate
,如下例所示:
<Button Width="32" Height="32" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Top">
<Button.Template>
<ControlTemplate>
<Button x:Name="btn">
<Grid>
<Path Fill="#00FFFFFF" Stretch="None" Data="F1M16,16L0,16 0,0 16,0z"/>
<Path x:Name="icn" Fill="Red" Stretch="None" Data="F1M12,12L4,12 4,4 12,4z M3,13L13,13 13,3 3,3z"/>
</Grid>
</Button>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Value="false">
<Setter TargetName="icn" Property="Fill" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=WindowState, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Value="Maximized">
<Setter TargetName="btn" Property="Background" Value="Blue"/>
<Setter TargetName="icn" Property="Data" Value="F1M11.999,10.002L10.998,10.002 10.998,5.002 5.998,5.002 5.998,4.001 11.999,4.001z M10.002,11.999L4.001,11.999 4.001,5.998 10.002,5.998z M5.002,3L5.002,5.002 3,5.002 3,13 10.998,13 10.998,10.998 13,10.998 13,3z"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>