【问题标题】:Windows Phone 7 - Setting style for specific control within selected ListBoxItemWindows Phone 7 - 为选定的 ListBoxItem 中的特定控件设置样式
【发布时间】:2011-11-12 13:01:36
【问题描述】:

假设我有这样的事情:

<Grid>
    <ListBox x:Name="list" 
        ItemsSource="{Binding SomeCollection, Mode=TwoWay}" 
        SelectedItem="{Binding SomeItem, Mode=TwoWay}">                    
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock x:Name="first" Text="{Binding SomeProperty}" />
                <TextBlock x:Name="second" Text="{Binding OtherProperty}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

现在,当 ListBoxItem 被选中时,我如何更改 TextBlock 的某些样式属性(例如 FontSize)?如果我想为所有 ListBoxItem 的内容设置 FontSize,那么我没有问题。这种情况在此处和网络上的其他地方都有很好的记录。

【问题讨论】:

    标签: xaml windows-phone-7 styles datatemplate


    【解决方案1】:

    我不会给你一个确切的解决方案,但是一个好的开始点:检查文件

    C:\Program Files\Microsoft SDKs\Windows Phone\vX.Y\Design\System.Windows.xaml
    

    您必须将 X.Y 与您的设置一起调整为 7.0/7.1。在那里,您会发现与 WP7/Silverlight 的所有基本 UI 控件所使用的控件模板完全相同。在 VisualStudio-or-whateverelse 中打开它并搜索:

    <Style TargetType="ListBoxItem">
      (... and immediatelly following ~40 lines of xaml)
    

    嗯,既然我已经打开了那个文件,那就是这个

        <!--x:Key="PhoneListBoxItem"-->
        <Style TargetType="ListBoxItem">
          <Setter Property="Background" Value="Transparent"/>
          <Setter Property="BorderThickness" Value="0" />
          <Setter Property="BorderBrush" Value="Transparent" />
          <Setter Property="Padding" Value="0" />
          <Setter Property="HorizontalContentAlignment" Value="Left"/>
          <Setter Property="VerticalContentAlignment" Value="Top"/>
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="ListBoxItem">
                <Border x:Name="LayoutRoot" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                  <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                      <VisualState x:Name="Normal"/>
                      <VisualState x:Name="MouseOver" />
                      <VisualState x:Name="Disabled">
                        <Storyboard>
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
                          </ObjectAnimationUsingKeyFrames>
                          <DoubleAnimation Storyboard.TargetName="ContentContainer" Storyboard.TargetProperty="Opacity" Duration="0" To=".5" />
                        </Storyboard>
                      </VisualState>
                    </VisualStateGroup>
                    <VisualStateGroup x:Name="SelectionStates">
                      <VisualState x:Name="Unselected"/>
                      <VisualState x:Name="Selected">
                        <Storyboard>
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentContainer" Storyboard.TargetProperty="Foreground">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                          </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                      </VisualState>
                    </VisualStateGroup>
                  </VisualStateManager.VisualStateGroups>
                  <ContentControl x:Name="ContentContainer" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
                    Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Foreground="{TemplateBinding Foreground}" />
                </Border>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
    

    这是您的 DEFAULT ListBoxItem 的完整样式 - 您要更改的内容。浏览代码并注意 'ContentPresenter' 和前面的 'VisualStateGroup x:Name="SelectionStates"'。

    ContentPresenter 是显示项目的 DataTemplate 的东西。
    该组中的 VisualStates 定义了从 正常 状态发生的变化,如果在列表元素上触发“选定状态”,则应该发生这种变化。
    一旦“选择状态”减少,元素会自动返回到未选择状态,并且他的视觉效果会随之而来。另请注意,未选择的视觉状态不会强制进行任何更改 - 因此它会保留您的普通 DataTemplate 样式。

    最后要注意的是,这是 ListBoxItem 的样式,不是 用于您的数据项,也不是您的数据模板。您的 DataTemplate 永远不会被触及,它直接由 ContentPresenter 显示。 ListBox 将您的所有项目包装在“ListBoxItem”实例中,然后显示这些 ListBoxItem 并将该样式应用于它们。

    恕我直言,这是您必须处理的重点。

    您可能希望根据需要复制和更改此样式,然后将您的 ListBox.ItemContainerStyle 设置为该 样式。其中一种方法是:

    <YourPage.Resources>
        <Style x:Key="mylistboxitemoverride" .....
            ........
        </Style>
    </YourPage.Resources>
    ...
    ...
    <ListBox ......... ItemContainerStyle="{StaticResource mylistboxitemoverride}"
        ...
        ...
    </ListBox>
    

    现在,诀窍是修改“已选择”VisualState,并使其不改变前景(这样做会重新设置您的两个文本框的样式!),而是一些其他属性,它只会影响您的一个 txb。不幸的是,这可能更难/更丑。在那一刻,我不知道如何使它“更漂亮”,而不是用您的 DataTemplate 硬替换 ContentPresenter 并像这样在 VisualState 中引用您的确切叶子文本框:

        <Style .... TargetType="ListBoxItem">
          <Setter Property="Background" Value="Transparent"/>
          <Setter Property="BorderThickness" Value="0" />
          <Setter Property="BorderBrush" Value="Transparent" />
          <Setter Property="Padding" Value="0" />
          <Setter Property="HorizontalContentAlignment" Value="Left"/>
          <Setter Property="VerticalContentAlignment" Value="Top"/>
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="ListBoxItem">
                <Border x:Name="LayoutRoot" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                  <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                      <VisualState x:Name="Normal"/>
                      <VisualState x:Name="MouseOver" />
                      <VisualState x:Name="Disabled">
                        <Storyboard>
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
                          </ObjectAnimationUsingKeyFrames>
                          <DoubleAnimation Storyboard.TargetName="SECOND" Storyboard.TargetProperty="Opacity" Duration="0" To=".5" /> <!-- #### RETARGETTED -->
                        </Storyboard>
                      </VisualState>
                    </VisualStateGroup>
                    <VisualStateGroup x:Name="SelectionStates">
                      <VisualState x:Name="Unselected"/>
                      <VisualState x:Name="Selected">
                        <Storyboard>
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SECOND" Storyboard.TargetProperty="Foreground"> <!-- #### RETARGETTED -->
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                          </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                      </VisualState>
                    </VisualStateGroup>
                  </VisualStateManager.VisualStateGroups>
    
                  <!-- #### INLINED YOUR DATATEMPLATE -->
                  <StackPanel Orientation="Vertical"
                              Margin="{TemplateBinding Padding}"
                              DataContext="{TemplateBinding Content}">  <!-- #### careful with the bindings. the DataCtx may be needed or is spurious. do check that! -->
                    <TextBlock Text="{Binding SomeProperty}" />  <!-- #### referenced from nowhere, so I removed the name -->
                    <TextBlock x:Name="SECOND" Text="{Binding OtherProperty}" />
                  </StackPanel>
    
                </Border>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
    

    这应该几乎是您想要的,或者至少非常接近它。我还没有测试过,您可能需要修改正确的数据绑定(我已经包含了 DataContent=binding:Content,但这是一个快速的猜测),并且您可能想要添加自己的动画。我想你现在有很多东西可以试验。玩得开心!

    【讨论】:

    【解决方案2】:

    将 TextBlock 上的样式设置为您想要的样式。

    <DataTemplate>
       <TextBlock x:Name="first" Style="{StaticResource Header}" Text="{Binding SomeProperty}" />
       <TextBlock x:Name="second" Style="{StaticResource Info}" Text="{Binding OtherProperty}" />
    </DataTemplate>
    

    【讨论】:

    • ..除了它将在所有处于正常状态的项目上全局工作,并且作者要求更改所选状态
    【解决方案3】:

    实现此目的的一种方法是,创建一个扩展的 ListBox 类,其中包含 SecondText 依赖项属性。然后只需使用 Blend 生成一个普通的 ListBox 样式,将 targat 类型更改为我的 ExtendedListBox。

    在此样式中,添加另一个 TextBlock 控件并将其 Text TemplateBinding 设置为 SecondText。您只需要在选定的视觉状态下更改此 TextBlock 的字体大小即可。

    另外,您可以创建附加属性 SecondText 并直接对其进行 TemplateBinding,而不是扩展 ListBox,但我尚未测试此方法。

    希望这可以帮助您入门。 :)

    【讨论】:

    • hm.. 当问题与 ListBoxItem 的模板有关时,您为什么建议更改 ListBox? @juarola 想要更改“选定状态”的视觉效果,以便在选择项目时只有第二个 tbox 重新设置样式(即突出显示)
    • 对不起,我的意思是 ListBoxItem,但再次想到这一点,实际上更容易接受 juarola 的建议,以 ListBoxItem 样式进行。对不起,我很尴尬,:(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2023-03-15
    • 2013-04-08
    • 1970-01-01
    相关资源
    最近更新 更多