WPF 资源库目标绑定到按钮内容的名称



我已经构建了一个ControlTemplate,用于窗口中的所有按钮,但有一个需要额外的触发器,当触发时会更改其内容值。很明显,我不想把这个触发器添加到控件模板上,因为它会影响使用这个控件模板的所有其他按钮。因此,我要做的是将数据触发器添加到按钮特定的样式中,然后引用内容名称,并在我认为很容易的样式中直接更改它。

这就是我目前所得到的:

<Button HorizontalAlignment="Right" 
        VerticalAlignment="Top" 
        Width="34"
        BorderThickness="0"
        Height="30"
        Padding="0"
        Click="OnMaximiseClick">
     <Button.Style>
         <Style TargetType="Button" BasedOn="{StaticResource WindowButtonStyle}">
             <Style.Triggers>
                 <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=WindowState}" Value="Maximised">
                     <Setter TargetName="MaxPath"
                             Property="Data"
                             Value="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z" />
                 </DataTrigger>
             </Style.Triggers>
         </Style>
     </Button.Style>
     <Path x:Name="MaxPath"
           Width="10"
           Height="10"
           Data="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z"
           SnapsToDevicePixels="True"
           Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" />
</Button>

问题在于Setter无法访问TargetName="MaxPath",我也尝试过{Binding ElementName=MaxPath},但陷入僵局。我知道我可以在按钮样式中再次构建ControlTemplate,但它有很多触发器,我不想在两个地方维护,我相信一定有一种方法可以快速轻松地做到这一点,但我就是看不到。

有没有引用它的Style中的按钮内容,或者我必须在该Buttons ControlTemplate中重建Path,然后在这个新的ControlTemplate中重新定义我的所有Triggers

转念一想,您不需要DataTrigger。只需将2个Path直接绑定到窗口状态即可。不过,您需要可重复使用的转换器。

下面是一个演示(使按钮可点击并将绑定添加到Fill):

xaml:

<Button>
    <Grid Width="10"
          Height="10">
        <Path Fill="Black"
              Data="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z"
              Visibility="{Binding WindowState, RelativeSource=RelativeSource FindAncestor, AncestorType=Window}, ConverterParameter=Invert, Converter={local:StateToVisibilityConverter}}" />
        <Path Fill="Black"
              Data="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z"
              Visibility="{Binding WindowState, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Converter={local:StateToVisibilityConverter}}" />
    </Grid>
</Button>

转换器:

public class StateToVisibilityConverter : MarkupExtension, IValueConverter
{
    public StateToVisibilityConverter() { }
    public override object ProvideValue(IServiceProvider serviceProvider) => this;
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var result = (WindowState)value == WindowState.Maximized;
        if ((string)parameter == "Invert")
            result = !result;
        return result ? Visibility.Visible : Visibility.Hidden;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }
}

第三个想法(仅xaml):

<Button>
    <Path Fill="Black"
          Width="10"
          Height="10">
        <Path.Style>
            <Style TargetType="Path">
                <Style.Setters>
                    <Setter Property="Data"
                            Value="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z" />
                </Style.Setters>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                 Value="Maximized">
                        <Setter Property="Data"
                                Value="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,1 1,3z" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Path.Style>
    </Path>
</Button>

您可能需要一个ControlTemplate:

<Button 
     ... [your other properties here] >
        <Button.Template>
            <ControlTemplate>
                <Path x:Name="MaxPath"
                    Width="10"
                   Height="10"
                   Data="F1M0,0L0,9 9,9 9,0 0,0 0,3 8,3 8,8 1,8 1,3z"
                   SnapsToDevicePixels="True"
                   Fill="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" />
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=WindowState}" Value="Minimised">
                        <Setter TargetName="MaxPath"
                         Property="Data"
                         Value="F1M0,10L0,3 3,3 3,0 10,0 10,2 4,2 4,3 7,3 7,6 6,6 6,5 1,5 1,10z M1,10L7,10 7,7 10,7 10,2 9,2 9,6 6,6 6,9 1,9z" />
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Button.Template>
    </Button>
</Grid>

如果需要,可以添加其他触发器。。

最新更新