How do I override the default behavior of a Silverlight ListBox?
The Silverlight ListBox control automatically moves the scroll box when the list item shown is clicked (if the list box is showing 5 items, click on the last item and all of the items are moved down one). I have a bug from my QA team telling me that causes confusion for our specific case. How can I override this behavior?
<ListBox x:Name="accountsListBox" Margin="8,65,8,8" SelectionChanged="accountsListBox_SelectionChanged" VirtualizingStackPanel.VirtualizationMode="Recycling">
<ListBox.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="Silver" Offset="1"/>
</LinearGradientBrush>
</ListBox.BorderBrush>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Height="19" Text="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_开发者_高级运维Loaded(object sender, RoutedEventArgs e)
{
List<string> names = new List<string>();
for (int i = 0; i < 100; i++)
{
names.Add("Name " + i);
}
this.accountsListBox.ItemsSource = names;
}
private void accountsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// this was an attempt but causes other unwanted behavior
//int selectedIndex = this.accountsListBox.SelectedIndex;
//this.accountsListBox.UpdateLayout();
//this.accountsListBox.ScrollIntoView(this.accountsListBox.Items[this.accountsListBox.SelectedIndex - 4]);
//this.accountsListBox.SelectedIndex = selectedIndex;
}
}
There is no need to override the behaviour. That is not a bug, but a feature for scrolling partially displayed list items into view.
The auto-scrolling behavior is caused by the list box being not quite tall enough for the 5 items (even though it may look it). Make the list box a few pixels taller and the problem will go away.
Hope this helps.
If you want to prevent the ListBox from auto-scrolling to display the entire selected item, give its ScrollViewer a custom style (see below) and in the template, give the vertical scrollbar a top and bottom margin of 1000. Next, give the listbox a top and bottom margin of 1000 and set its style to one that uses the modified scrollviewer style. Then, clip the listbox (as below) so that it doesn't cover up whatever might be above it. Finally, whenever you add items to your listbox, first add an empty ListBoxItem that has a height of 1000, and then append at the end of items another empty ListBoxItem with a height of 1000.
<Style x:Key="ScrollViewerStyleForWhiteBg" TargetType="ScrollViewer">
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Scrolling">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VerticalScrollBar"/>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="HorizontalScrollBar"/>
</Storyboard>
</VisualState>
<VisualState x:Name="NotScrolling"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Margin="{TemplateBinding Padding}">
<ScrollContentPresenter x:Name="ScrollContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}"/>
<ScrollBar x:Name="VerticalScrollBar" Margin="0,1000,0,1000" HorizontalAlignment="Right" Height="Auto" IsHitTestVisible="False" IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Opacity="0" Orientation="Vertical" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{TemplateBinding VerticalOffset}" ViewportSize="{TemplateBinding ViewportHeight}" VerticalAlignment="Stretch" Width="5" Background="Red" />
<ScrollBar x:Name="HorizontalScrollBar" HorizontalAlignment="Stretch" Height="5" IsHitTestVisible="False" IsTabStop="False" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Opacity="0" Orientation="Horizontal" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{TemplateBinding HorizontalOffset}" ViewportSize="{TemplateBinding ViewportWidth}" VerticalAlignment="Bottom" Width="Auto" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ListBoxStyleForReader" TargetType="ListBox">
<Setter Property="Padding" Value="0"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="ScrollViewer" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}"
Style="{StaticResource ScrollViewerStyleForWhiteBg}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ListBox x:Name="_myList" Margin="0,-1000,0,-1000" Style="{StaticResource ListBoxStyleForReader}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ListBox.Clip>
<RectangleGeometry Rect="0,1000,480,10000" />
</ListBox.Clip>
</ListBox>
_myList.Insert(0, new ListBoxItem() { Height = 1000 });
_myList.Add(new ListBoxItem() { Height = 1000 });
精彩评论