如何在MVVM WPF应用程序中控制ListBox的滚动位置

Job*_*Joy 24 c# wpf listbox mvvm scrollviewer

我有一个大的ListBox启用了垂直滚动,我的MVVM有New和Edit ICommands.我在集合的末尾添加了新项目,但是当我调用MVVM-AddCommand时,我还希望滚动条自动定位到End.我也从应用程序的其他部分创建一个可编辑的项目(通过调用带有特定行项的EditCommand),以便我的ListBoxItem使用DataTrigger进入编辑模式,但是如何将该特定行(ListBoxItem)带到视图中通过调整滚动位置.

如果我在View端进行,我可以调用listBox.ScrollInToView(lstBoxItem).但是从MVVM角度解决这个常见Scroll问题的最佳方法是什么.

小智 28

我通常会IsSynchronizedWithCurrentItem="True"ListBox.然后我添加一个SelectionChanged处理程序,并始终将所选项目带入视图,代码如下:

    private void BringSelectionIntoView(object sender, SelectionChangedEventArgs e)
    {
        Selector selector = sender as Selector;
        if (selector is ListBox)
        {
            (selector as ListBox).ScrollIntoView(selector.SelectedItem);
        }
    }
Run Code Online (Sandbox Code Playgroud)

从我的VM我可以获得默认的集合视图,并使用其中一种MoveCurrent*()方法来确保正在编辑的项目是当前项目.

CollectionViewSource.GetDefaultView(_myCollection).MoveCurrentTo(thisItem);
Run Code Online (Sandbox Code Playgroud)

注意:编辑ListBox.ScrollIntoView()用于容纳虚拟化


Kel*_*lly 7

在MVVM中使用它可以通过附加的行为轻松完成,如下所示:

using System.Windows.Controls;
using System.Windows.Interactivity;

namespace Jarloo.Sojurn.Behaviors
{
    public sealed class ScrollIntoViewBehavior : Behavior<ListBox>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.SelectionChanged += ScrollIntoView;
        }

        protected override void OnDetaching()
        {
            AssociatedObject.SelectionChanged -= ScrollIntoView;
            base.OnDetaching();
        }

        private void ScrollIntoView(object o, SelectionChangedEventArgs e)
        {
            ListBox b = (ListBox) o;
            if (b == null)
                return;
            if (b.SelectedItem == null)
                return;

            ListBoxItem item = (ListBoxItem) ((ListBox) o).ItemContainerGenerator.ContainerFromItem(((ListBox) o).SelectedItem);
            if (item != null) item.BringIntoView();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在查看广告中,此引用位于顶部:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Run Code Online (Sandbox Code Playgroud)

这样做:

<ListBox ItemsSource="{Binding MyData}" SelectedItem="{Binding MySelectedItem}">
         <i:Interaction.Behaviors>
             <behaviors:ScrollIntoViewBehavior />
         </i:Interaction.Behaviors>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

现在,当SelectedItem更改时,行为将为您执行BringIntoView()调用.


Vah*_*idN 5

这是已接受答案的附加属性形式:

using System.Windows;
using System.Windows.Controls;

namespace CommonBehaviors
{
    public static class ScrollCurrentItemIntoViewBehavior
    {
        public static readonly DependencyProperty AutoScrollToCurrentItemProperty =
            DependencyProperty.RegisterAttached("AutoScrollToCurrentItem",
                typeof(bool), typeof(ScrollCurrentItemIntoViewBehavior),
                new UIPropertyMetadata(default(bool), OnAutoScrollToCurrentItemChanged));

        public static bool GetAutoScrollToCurrentItem(DependencyObject obj)
        {
            return (bool)obj.GetValue(AutoScrollToCurrentItemProperty);
        }

        public static void OnAutoScrollToCurrentItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var listBox = obj as ListBox;
            if (listBox == null) return;

            var newValue = (bool)e.NewValue;
            if (newValue)
                listBox.SelectionChanged += listBoxSelectionChanged;
            else
                listBox.SelectionChanged -= listBoxSelectionChanged;
        }

        static void listBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var listBox = sender as ListBox;
            if (listBox == null || listBox.SelectedItem == null || listBox.Items == null) return;

            listBox.Items.MoveCurrentTo(listBox.SelectedItem);
            listBox.ScrollIntoView(listBox.SelectedItem);
        }

        public static void SetAutoScrollToCurrentItem(DependencyObject obj, bool value)
        {
            obj.SetValue(AutoScrollToCurrentItemProperty, value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

<ListBox ItemsSource="{Binding}"
          IsSynchronizedWithCurrentItem="True"
          behaviors:ScrollCurrentItemIntoViewBehavior.AutoScrollToCurrentItem="True">
Run Code Online (Sandbox Code Playgroud)