Windows Phone 7 - 设置选定 ListBoxItem 内特定控件的样式

发布于 2024-12-03 14:21:37 字数 710 浏览 3 评论 0原文

假设我有这样的东西:

<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,那么我就没有问题了。这种情况在此处和网络上的其他地方都有详细记录。

let's say i have something like this:

<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>

Now, how do i alter some style property (f.ex. FontSize) of only the TextBlock called "second" when a ListBoxItem gets selected? If i'd like to set the FontSize for all ListBoxItem's contents, then i'd have no problem. That scenario is quite well documented here and elsewhere on the web.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ゃ人海孤独症 2024-12-10 14:21:37

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

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

你必须将 XY 调整为 7.0/7.1 的文件以及你的设置。在那里您会发现与 WP7/Silverlight 的所有基本 UI 控件所使用的控件模板完全相同。在 VisualStudio 或其他任何程序中打开它并搜索:

<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,但这是一个快速猜测),并且可能您会想要添加自己的动画。我想你现在有很多东西可以尝试。玩得开心!

I will not give you an exact solution, but a good point to start with: check out the file

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

you have to adjust X.Y to 7.0/7.1 along with your setup. There you will find exactly the same Control-Templates that are being used all the basic UI Controls of the WP7/Silverlight. Open it in VisualStudio-or-whateverelse and search for:

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

ah well, since I've opened that file, here's that

    <!--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>

This is the complete style for your DEFAULT ListBoxItem - the thing you want to alter. Skim through the code and note the 'ContentPresenter' and preceding 'VisualStateGroup x:Name="SelectionStates"'.

ContentPresenter is the thing that will show your DataTemplate for the item.
VisualStates in that group define the changes from the normal state that should occur if a "selected state" is fired of on an list element.
Once the "selection state" diminishes, the element returns to the unselected state automatically and his visuals follow. Note also that the Unselected visual state does not enforce any changes - so it preserves your plain DataTemplate style.

The last thing to notice is that this is a style for ListBoxItem, and not for your data-item, nor your data-template. Your DataTemplate is never touched, it is directly displayed by the ContentPresenter. The ListBox wraps all your items in "ListBoxItem" instances, then displays those ListBoxItems and applies that style to them.

IMHO, this is the point you will have to work with.

You may want to copy&alter this style to your needs, and then set your ListBox.ItemContainerStyle to that new style. One of the ways is:

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

Now, the trick is to modify the 'Selected' VisualState, and make it alter not the Foreground (doing that would restyle both your TextBoxes!), but some other property which will affect only one of your txbs. Unfortunatelly, that may be harder/uglier. I don't at that moment any idea how to make it "prettier" than hard-replacing the ContentPresenter with your DataTemplate and referencing your exact leaf-textbox in the VisualState like that:

    <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>

This should be almost what you want, or at least very close to it. I have not tested it, you may need to tinker with proper data-binding (I've included a DataContent=binding:Content, but that's a quick guess) and probably you will want to add your own animations. I think you have now tons of bits to experiment with. Have fun!

我纯我任性 2024-12-10 14:21:37

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

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

Set the Style on the TextBlock to a Style that does what you want.

<DataTemplate>
   <TextBlock x:Name="first" Style="{StaticResource Header}" Text="{Binding SomeProperty}" />
   <TextBlock x:Name="second" Style="{StaticResource Info}" Text="{Binding OtherProperty}" />
</DataTemplate>
逆光飞翔i 2024-12-10 14:21:37

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

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

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

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

one way to achieve this is, create an extended ListBox class with a SecondText dependency property in it. Then just use Blend to generate a normal ListBox style, change the targat type to my ExtendedListBox.

In this style, add another TextBlock control and set its Text TemplateBinding to the SecondText. You just need to alter this TextBlock's font size in the selected visual state.

Also, rather than extending the ListBox, you might be able to create an attached property SecondText and just TemplateBinding to it directly, but I haven't tested this method yet.

Hope this can get you started with. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文