воскресенье, 25 марта 2012 г.

Тонкости работы ListBox в Silverlight

Задача состояла в разработке небольшого Silverlight приложения, отображающего определенный контент. Логика работы в данном случае не имеет значения, так как проблемы проявились с разметкой. 



Разметка:



xmlns:c="clr-namespace:SAC_Test"

* This source code was highlighted with Source Code Highlighter.


<UserControl.Resources>
    <c:TestData x:Key="testData" x:Name="testData"/>
</UserControl.Resources>


* This source code was highlighted with Source Code Highlighter.


<Style TargetType="ListBox" >
  <Setter Property="ItemTemplate">
    <Setter.Value>
      <DataTemplate>
        <TextBox TextWrapping="Wrap" Text="{Binding}"> </TextBox>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>


* This source code was highlighted with Source Code Highlighter.


<Grid Name="grdMap" Grid.Row="1">
  <Grid.ColumnDefinitions>
     <ColumnDefinition Width="250"/>
       <ColumnDefinition Width="Auto"/>
     <ColumnDefinition/>
  </Grid.ColumnDefinitions>
  <sdk:GridSplitter Grid.Column="1"
           HorizontalAlignment="Center"
           VerticalContentAlignment="Stretch"
           Width="3"/>
  <Grid Name="grdIncidents" Grid.Column="0">
     <ListBox x:Name="lsbIncidents" ItemsSource="{StaticResource testData}">
     </ListBox>
  </Grid>     
</Grid>


* This source code was highlighted with Source Code Highlighter.



Класс TestData:

namespace SAC_Test
{
  public class TestData : List
  {
    public TestData()
    {
      Add("aaaaaaaaaaaa aaaaaaaaa aaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaa");
      Add("aaaaaaaaaaaa aaaaaaaaa aaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaa");
      Add("aaaaaaaaaaaa aaaaaaaaa aaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaaa aaaaaaaaaaa");
    }
  }
}


* This source code was highlighted with Source Code Highlighter.


Казалось бы, все просто и предсказуемо, за исключением одного НО! TextBox не изменяет своего размера при перемещении GridSplitter'а и текст внутри него не переносится по словам:
Текст не переносится по словам

После долгих и упорных, местами откровенно шаманских, попыток добится предсказуемого отображения элементов ListBox'а, появился следующий код, который решал проблему:
Изменения коснулись стиля элемента ListBox:

<Style TargetType="ListBox" >
  <Setter Property="ItemTemplate">
    <Setter.Value>
      <DataTemplate>
        <TextBox TextWrapping="Wrap" Text="{Binding}"> </TextBox>
      </DataTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="Template">
  <Setter.Value>
    <ControlTemplate>
    </ControlTemplate>
  </Setter.Value>
  </Setter>

</Style>


* This source code was highlighted with Source Code Highlighter.



Соответственно, результат:

Теперь текст отображается корректно

Но как-то это, согласитесь, странно: задали пустой шаблон для всего элемента управления — и поведение стало предсказуемым. 
Решил разобраться в этом подробнее. В MSDN была найдена разметка, реализующая шаблон по-умолчанию для ListBox:msdn.microsoft.com

Вот часть разметки с MSDN, в которой кроется разгадка:


<ScrollViewer x:Name="ScrollViewer"
       Padding="{TemplateBinding Padding}"
     Background="{TemplateBinding Background}"
     BorderBrush="Transparent"
       BorderThickness="0"
     TabNavigation="{TemplateBinding TabNavigation}">
  <ItemsPresenter />
</ScrollViewer>


* This source code was highlighted with Source Code Highlighter.

...

Разработчики обернули ItemsPresenter ScrollViewer'ом. У ScrollViewer'a свойство HorizontalScrollBarVisibility имеет значение «auto», и, как следствие, вместо переноса текста просто появляется полоска прокрутки.
Решение:

Решений может быть несколько.
Во-первых, можно оставить тот вариант, который был предложен выше, где к стилю ListBox'a добавляется пустой ControlTemplate.
Ну и во-вторых, можно взять шаблон из MSDN и дополнить стиль ScrollViewer'a:

<UserControl.Resources>
...
  <Style TargetType="ScrollViewer">
      <Setter Property="HorizontalScrollBarVisibility" Value="Disabled"/>
    </Style>
...
</UserControl.Resources>


* This source code was highlighted with Source Code Highlighter.



Но второй вариант будет работать, только если полностью переопределить стиль ListBox (или скопировать XAML разметку с MSDN).
Если в дальнейшем потребуется горизонтальная полоса прокрутки, то просто в нужном месте локально задаем этому свойству значение. Локальное значение имеет больший приоритет, так что проблем не возникнет.

P.S. Я остановился на первом варианте. Все прекрасно работает.

Удачной вам разработки!

Комментариев нет:

Отправить комментарий