Windows Phone 7 - Настройка стиля для определенного элемента управления в выбранном ListBoxItem - PullRequest
0 голосов
/ 08 сентября 2011

скажем, у меня есть что-то вроде этого:

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

Теперь, как мне изменить какое-либо свойство стиля (например, FontSize) только для TextBlock, называемый "second"когда ListBoxItem будет выбран?Если бы я хотел установить FontSize для всего содержимого ListBoxItem, то у меня не было бы проблем.Этот сценарий довольно хорошо задокументирован здесь и в других местах в Интернете.

Ответы [ 3 ]

6 голосов
/ 09 сентября 2011

Я не дам вам точного решения, но для начала неплохо: посмотрите файл

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

Вы должны настроить X.Y на 7.0 / 7.1 вместе с настройками. Там вы найдете точно такие же шаблоны элементов управления, которые используются всеми основными элементами управления пользовательского интерфейса WP7 / Silverlight. Откройте его в 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, затем отображает эти ListBoxItems и применяет к ним этот стиль.

ИМХО, именно с этим вам и придется работать.

Возможно, вы захотите скопировать и изменить этот стиль в соответствии со своими потребностями, а затем установить для ListBox.ItemContainerStyle этот новый стиль. Один из способов:

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

Теперь уловка состоит в том, чтобы изменить «Выбранное» VisualState и сделать так, чтобы он изменял не передний план (делая это, чтобы перестроить оба ваших TextBoxes!), А некоторое другое свойство, которое повлияет только на один из ваших txbs. К сожалению, это может быть сложнее / уродливее. В тот момент я не представлял, как сделать его «красивее», чем жесткая замена ContentPresenter на ваш DataTemplate и ссылка на ваше точное текстовое поле листа в 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, но это быстрое предположение), и, возможно, вы захотите добавить свои собственные анимации. Я думаю, у вас есть куча экспериментов. Веселись!

0 голосов
/ 08 сентября 2011

Один из способов добиться этого - создать расширенный класс ListBox со свойством зависимостей SecondText.Затем просто используйте Blend для генерации обычного стиля ListBox, измените тип targat на мой ExtendedListBox.

В этом стиле добавьте еще один элемент управления TextBlock и установите его Text TemplateBinding для SecondText.Вам просто нужно изменить размер шрифта этого TextBlock в выбранном визуальном состоянии.

Кроме того, вместо расширения ListBox, вы можете создать прикрепленное свойство SecondText и просто привязать к нему TemplateBinding, но я неt еще не опробовал этот метод.

Надеюсь, это поможет вам начать.:)

0 голосов
/ 08 сентября 2011

Установите стиль в TextBlock на стиль, который делает то, что вы хотите.

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