通过viewmodel将scrollviewer滚动到顶部

D.Y*_*ung 9 wpf scroll mvvm

我正在使用带有MVVM模式的ScrollViewer,并且ScrollViewer包含了一个项目列表,例如

<ScrollViewer>
  <ListView>
    <ListView.View>
        <GridView>
            <GridViewColumn
                Header = "Name"
                DisplayMemberBinding="{Binding Path=Name}"
            />              
        </GridView>
    </ListView.View>
  </ListView>
</ScrollViewer>
Run Code Online (Sandbox Code Playgroud)

列表视图的项目绑定到viewmodel中的对象集合.我希望每当从集合中添加或删除项目时,scrollviewer都会滚动到顶部.
我需要viewmodel来触发事件,而不是ScrollToTop()在视图的代码隐藏中使用该方法.

小智 22

恕我直言,最明智的方法是使用"行为"通过AttachedProperty.An AttachedProperty是一种扩展现有控件功能的机制.

首先,创建一个类来保存AtachedProperty,例如:

public class ScrollViewerBehavior
{
    public static bool GetAutoScrollToTop(DependencyObject obj)
    {
        return (bool)obj.GetValue(AutoScrollToTopProperty);
    }

    public static void SetAutoScrollToTop(DependencyObject obj, bool value)
    {
        obj.SetValue(AutoScrollToTopProperty, value);
    }

    public static readonly DependencyProperty AutoScrollToTopProperty =
        DependencyProperty.RegisterAttached("AutoScrollToTop", typeof(bool), typeof(ScrollViewerBehavior), new PropertyMetadata(false, (o, e) =>
            {
                var scrollViewer = o as ScrollViewer;
                if (scrollViewer == null)
                {
                    return;
                }
                if ((bool)e.NewValue)
                {
                    scrollViewer.ScrollToTop();
                    SetAutoScrollToTop(o, false);
                }
            }));
}
Run Code Online (Sandbox Code Playgroud)

这个附加属性允许ScrollViewer"神奇地"拥有类型的新属性Boolean,就像DependencyProperty在你的XAML中一样.如果将此属性绑定到ViewModel中的标准属性,例如:

private bool _reset;
public bool Reset
{
    get { return _reset; }
    set
    {
        _reset = value;
        if(PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Reset"));
    }
}
Run Code Online (Sandbox Code Playgroud)

(再次,名称取决于您)然后将此Reset属性设置为true,您ScrollViewer将滚动到顶部.我将其命名AtachedProperty为AutoScrollToTop,但名称对此并不重要.

XAML将是这样的:

<ScrollViewer my:ScrollViewerBehavior.AutoScrollToTop="{Binding Reset, Mode=TwoWay}">
    <ListView>
        <ListView.View>
            <GridView>
                <GridViewColumn
                    Header = "Name"
                    DisplayMemberBinding="{Binding Path=Name}"
                />
            </GridView>
        </ListView.View>
    </ListView>
</ScrollViewer>
Run Code Online (Sandbox Code Playgroud)

注意:my是您的ScrollViewerBehavior类所在的命名空间.例如:xmlns:my="clr-namespace:MyApp.Behaviors"

最后,您在ViewModel中唯一需要做的就是Reset = true在您的情况下,在您添加或删除集合中的元素时设置.


Ami*_*mit -1

我也遇到过类似的情况,我需要以编程方式分配 ScrollViewer 的 Horizo​​ntalOffset 和 VerticalOffset。恐怕对此没有直接的约束机制。我所做的是一种解决方法(相信我,我仍然不喜欢我遵循的方法,但我没有找到任何其他选择)。这是我的建议:

挂钩 ScrollViewer 的 Loaded 事件,将发送者对象强制转换为 ScrollViewer 并将其分配给 DataContext 中的属性(意味着您需要在 DataContext 中保留 ScrollViewer 属性,该属性将在 UI 中保存 ScrollViewer 的引用)。在 ViewModel 中连接 ObservableCollection 的 CollectionChanged 事件并使用 ScrollViewer 属性,您可以调用 ScrollToTop() 等方法。

这只是一种变通方法。我仍在寻找更好的解决方案。