更改选定的索引时,在列表框中显示所选项目滚动ListBox

时间:2017-06-20 13:57:15

标签: c# wpf xaml mvvm listbox

我有一个显示书籍的列表框。 SelectedIndexCurrentindex绑定到Viewmodel中的Properties。 ListBox下面是两个按钮,简单地从Viewmodel中的SelectedIndex属性添加(next)或减去(last)一个。

<DockPanel LastChildFill="False">
    <ListBox DockPanel.Dock="Top"
             ItemsSource="{Binding Books, Mode=OneWay}"
             SelectedItem="{Binding CurrentBook, Mode=TwoWay}" 
             SelectedIndex="{Binding SelectedIndex}"
             />
    <StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom">
        <Button Content="Last" Command="{Binding ChangeBook}" CommandParameter="last"/>
        <Button Content="Next" Command="{Binding ChangeBook}" CommandParameter="next"/>
    </StackPanel>
</DockPanel>

点击NextLast按钮可更改ListBox的索引。不会发生的事情是,当索引向用户推断出可见区域时,ListBox不会向下滚动,保持所选索引可见。

我想知道如何实现,除非用户滚动,否则SelectedItem始终在ListBox中可见。
当然,我想做到这一点,而不是在这样做时打破MVVM模式。

1 个答案:

答案 0 :(得分:1)

以下是在不违反MVVM的情况下如何做到这一点。

<ListBox DockPanel.Dock="Top"
         ItemsSource="{Binding Books, Mode=OneWay}"
         SelectedItem="{Binding CurrentBook, Mode=TwoWay}" 
         SelectedIndex="{Binding SelectedIndex}"
         SelectionChanged="ListBox_SelectionChanged"
         />

代码背后:

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var lb = (ListBox)sender;

    lb.ScrollIntoView(lb.SelectedItem);
}

这是一个更可敬的方式。使用这些东西后面的代码没有什么错误,但如果在不同的视图中使用这样的行为不止一次,使用附加属性比复制和粘贴更方便事件处理程序此外,它现在可以用在像DataTemplate这样的上下文中,其中可能没有代码。

预先有一些代码,但您可以轻松地将附加属性添加到项目中的任何ListBox

public static class ListBoxExtensions
{
    #region ListBoxExtensions.KeepSelectedItemVisible Attached Property
    public static bool GetKeepSelectedItemVisible(ListBox lb)
    {
        return (bool)lb.GetValue(KeepSelectedItemVisibleProperty);
    }

    public static void SetKeepSelectedItemVisible(ListBox lb, bool value)
    {
        lb.SetValue(KeepSelectedItemVisibleProperty, value);
    }

    public static readonly DependencyProperty KeepSelectedItemVisibleProperty =
        DependencyProperty.RegisterAttached("KeepSelectedItemVisible", typeof(bool), typeof(ListBoxExtensions),
            new PropertyMetadata(false, KeepSelectedItemVisible_PropertyChanged));

    private static void KeepSelectedItemVisible_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var lb = (ListBox)d;

        if ((bool)e.NewValue)
        {
            lb.SelectionChanged += ListBox_SelectionChanged;
            ScrollSelectedItemIntoView(lb);
        }
        else
        {
            lb.SelectionChanged -= ListBox_SelectionChanged;
        }
    }

    private static void ScrollSelectedItemIntoView(ListBox lb)
    {
        lb.ScrollIntoView(lb.SelectedItem);
    }

    private static void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ScrollSelectedItemIntoView((ListBox)sender);
    }
    #endregion ListBoxExtensions.KeepSelectedItemVisible Attached Property
}

XAML:

<ListBox DockPanel.Dock="Top"
         ItemsSource="{Binding Books, Mode=OneWay}"
         SelectedItem="{Binding CurrentBook, Mode=TwoWay}" 
         SelectedIndex="{Binding SelectedIndex}"
         local:ListBoxExtensions.KeepSelectedItemVisible="True"
         />