【问题标题】:WPF XAML Relative Source Not Updating In Data Trigger [duplicate]WPF XAML相对源未在数据触发器中更新[重复]
【发布时间】:2021-02-15 21:57:41
【问题描述】:

我将问题分解为更简单的形式,但我仍然无法弄清楚。我有一个空白 WPF 应用程序,主 XAML 文件中有一个按钮。

该按钮有 2 个图标,这些图标会根据窗口的状态而变化。图标的画笔属性绑定到按钮的前景属性,该属性会在窗口处于活动状态或非活动状态时发生变化。一切都很好,直到我最大化窗口但没有显示第二个图标。我知道最大化窗口状态正在工作,因为我可以将按钮的背景更改为蓝色。

我收到绑定失败错误“找不到源:RelativeSource FindAncestor, AncestorType='System.Windows.Controls.Button', AncestorLevel='1'。”

我对可以正常工作的默认状态使用相同的绑定。它只是在第二个图标的数据触发器内更新失败。

Snapshot showing the problem & error

<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 提出的类似问题:

Datatrigger in WPF Style: Change content doesn't work

通过将图标的路径内容放在Resources 中并使用DataTrigger 中的内容也可以。但是,使用这种方法,设计器中不会显示图标,因此我更喜欢 cmets 中的其他两种方法。

我已将 Sergey 的答案标记为已接受的答案,作为对 RelativeSource Binding FindAncestor Mode 的解释,我出错的地方非常有用。

再次感谢大家!

【问题讨论】:

    标签: wpf xaml data-binding triggers relativesource


    【解决方案1】:

    如何使用“ControlTemplate”而不是在 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来改变内容。

    【讨论】:

      【解决方案2】:

      您误解了RelativeSource Binding FindAncestor Mode 的工作原理。它确实以这样一种方式工作,即属性在任何给定时间都绑定到所需类型的最近祖先。在创建绑定时,只能找到一次祖先。 在您的情况下,在 DataTrigger 设置器中创建的 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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-06-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多