wpf - VisualStateManager VisualGroup 优先级

标签 wpf xaml togglebutton visualstatemanager

我正在尝试将我的 ControlTemplate 中的 VisualStateManager 用于 ToggleButton。我希望 ToggleButton 在选中时看起来是一种方式,在未选中时看起来是另一种方式。我还希望 ToggleButton 在禁用时看起来有所不同。我遇到的问题是 Unchecked VisualState 似乎胜过 Disabled VisualState。

文档指出“每个 VisualStateGroup 都包含一组相互排斥的 VisualState 对象。”这很好,但是组之间的互斥性呢?

无论如何,这是我的 ControlTemplate。如何让 TextBlock 为三种状态中的每一种使用不同的颜色;选中、未选中和禁用?

<Style x:Key="GraphToggleButtonStyle" TargetType="{x:Type ToggleButton}">
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="Cursor" Value="Hand" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Border Background="Transparent">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="TextBlock" To="Pink" Duration="0" />
                                </Storyboard>
                            </VisualState>
                       </VisualStateGroup>
                        <VisualStateGroup x:Name="CheckStates">
                            <VisualState x:Name="Checked">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="TextBlock" To="#3AA5DB" Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unchecked">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="TextBlock" To="Green" Duration="0" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Indeterminate" />
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="Border" CornerRadius="4" Background="{TemplateBinding Background}">
                        <StackPanel>
                            <TextBlock Name="TextBlock" FontFamily="/Resources/#Entypo" Text="🔆" FontSize="87" Foreground="#909090" HorizontalAlignment="Center" Margin="0,-25,0,0" />
                            <TextBlock FontFamily="Proxima Nova Rg" Text="Stimulator" FontSize="18" Foreground="{StaticResource BlackBrush}" HorizontalAlignment="Center" Margin="0,12,0,0" />
                        </StackPanel>
                    </Border>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

最佳答案

Each VisualStateGroup contains a collection of VisualState objects that are mutually exclusive

这是事实。然而,还有一个要求,即每个 VisualState 不应影响相同的属性。在这种情况下,您的 Unchecked 状态和 Disabled 状态会影响同一元素的相同属性 Foreground

所以我认为我们对此没有任何优雅的解决方案。我们只有这个变通办法(这实际上在 WPF 中设置元素样式时经常使用)。我们需要一些名为 DisabledTextBlock 的假元素,它应该与原始元素 TextBlock 放在同一个网格中。一旦 Disabled 状态到来,该假元素应该显示并隐藏原始元素,并隐藏 Unchecked(或 Checked)状态的所有效果并带来效果Disabled 到前面。这是工作代码:

<ControlTemplate TargetType="{x:Type ToggleButton}">
   <Border Background="Transparent">
     <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CheckStates">
           <!-- unchanged -->
        </VisualStateGroup>
        <VisualStateGroup x:Name="CommonStates">                            
          <VisualState Name="Disabled">
            <Storyboard>
             <DoubleAnimation Storyboard.TargetProperty="Opacity" 
                       Storyboard.TargetName="DisabledTextBlock" To="1" Duration="0" />
            </Storyboard>
          </VisualState>                            
         </VisualStateGroup>                        
      </VisualStateManager.VisualStateGroups>
      <Border x:Name="Border" CornerRadius="4" Background="{TemplateBinding Background}">
         <StackPanel>
           <Grid>
             <TextBlock Name="TextBlock" FontFamily="/Resources/#Entypo" Text="🔆"
                        FontSize="87" Foreground="#909090" HorizontalAlignment="Center"
                        Margin="0,-25,0,0"  Background="Transparent"/>
             <!-- the fake element -->
             <TextBlock Name="DisabledTextBlock" Opacity="0" 
                        FontFamily="{Binding FontFamily, ElementName=TextBlock}" 
                        Text="{Binding Text,ElementName=TextBlock}" 
                        FontSize="{Binding FontSize,ElementName=TextBlock}" 
                        Foreground="Pink" HorizontalAlignment="Center" 
                        Margin="{Binding Margin, ElementName=TextBlock}"  
                        Background="Transparent"
                        FontStyle="{Binding FontStyle,ElementName=TextBlock}" 
                        FontWeight="{Binding FontSize, ElementName=TextBlock}"/>
           </Grid>
           <TextBlock FontFamily="Proxima Nova Rg" Text="Stimulator" FontSize="18" 
                      Foreground="Black" HorizontalAlignment="Center" Margin="0,12,0,0"/>
         </StackPanel>
       </Border>
     </Border>
 </ControlTemplate>

您可能有一些新需求,但是这里的思路很明确。这是我认为的唯一解决方法。

关于wpf - VisualStateManager VisualGroup 优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26520661/

相关文章:

c# - 指南针 UI 和指针

Javascript:切换功能不起作用

javascript - Angular - 使用两个按钮设置单个 bool 值(通过/失败)

c# - 所选项目ComboBox没有显示正确的ID WPF

c# - WPF - 从代码隐藏/附加行为绑定(bind)到显式实现的接口(interface)属性

c# - Windows 8 Metro App 制作设置弹出窗口

javascript - 使用 CSS Togglebuttons 和 .on() 绑定(bind)器生成动态字段

c# - ShowBalloonTip 不工作

.net - INotifyPropertyChanged 属性名称 - 硬编码与反射?

c# - 如何将选定的文件详细信息传递到另一个页面 - UWP?