Silverlight ScrollViewer不滚动

时间:2010-01-26 22:34:36

标签: c# silverlight

enter code here每当我从后面的代码调用ScrollToVerticalOffset方法时,Silverlight中的ScrollViewer都不会垂直滚动。

基本上,我的View(UserControl)包含ScrollViewer。我从我的ViewModel调用一个动作,该动作触发View的代码隐藏中的事件,该事件将VerticalOffset设置为特定值。

首先,我知道这非常难看。理想情况下,我希望我可以有一个可附加的属性,我可以绑定到我的ViewModel中的属性,当设置时,将导致VerticalOffset属性(我知道是只读的)更新,并滚动ScrollViewer。

ScrollViewer包含动态内容。因此,如果用户正在ScrollViewer中查看内容,并向下滚动一半,然后单击一个按钮,则新内容将加载到ScrollViewer中。问题是ScrollViewer的垂直偏移不会被重置,因此用户必须向上滚动才能读取内容。所以,我的解决方案是能够控制ViewModel的垂直偏移,我已经绞尽脑汁,无法找到可行的解决方案,所以我正在找人帮忙。

顺便说一句 - 我已经将我编写的类中的代码包含在一个可附加属性中。此属性绑定到ViewModel中的属性。当我在ViewModel中设置属性时,它会正确触发此类中的PropertyChanged回调方法,该方法然后调用ScrollViewer的ScrollToVerticalOffset方法,但ScrollViewer仍然不会滚动。

public class ScrollViewerHelper
{
    public static readonly DependencyProperty BindableOffsetProperty =
    DependencyProperty.RegisterAttached("BindableOffset", typeof(double), typeof(ScrollViewerHelper),
    new PropertyMetadata(OnBindableOffsetChanged));

    public static double GetBindableOffset(DependencyObject d)
    {
        return (double)d.GetValue(BindableOffsetProperty);
    }

    public static void SetBindableOffset(DependencyObject d, double value)
    {
        d.SetValue(BindableOffsetProperty, value);
    }

    private static void OnBindableOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ScrollViewer scrollViewer = d as ScrollViewer;

        if (scrollViewer != null)
        {
            scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

在我看来,这种方法有点时髦,因为我认为ScrollViewer和VerticalScrollOffset都是“View”实体,它们与ViewModel的关系应该很少(或没有)。看起来这可能会迫使MVVM有点过多,并且在创建附加依赖项属性时创建了大量额外工作,并且基本上试图使绑定的Offset ViewModel属性与ScrollViewer的只读VerticalScrollOffset保持同步。

我并非确切地确定您要实现的目标,但听起来当您将某个动态元素添加到ScrollViewer的基础面板时,您正在尝试滚动到指定的偏移量。就个人而言,我只想在我的视图中使用一些代码来处理这种行为,而忘记将它绑定到ViewModel。

在Silverlight 3中执行此类操作的一个非常好的方法是使用Blend行为。您在C#中编写了一些行为代码,然后可以声明性地将其附加到XAML中的元素。这使它可以重复使用,而不是代码隐藏。您的项目必须引用System.Windows.Interactivity DLL,它是Blend SKD的一部分。

这是一个简单的Blend行为的简单示例,您可以添加到ScrollViewer,只要ScrollViewer的基础内容的大小发生变化,它就会滚动到指定的偏移量:

public class ScrollToOffsetBehavior : Behavior<ScrollViewer>
{
    private FrameworkElement contentElement = null;

    public static readonly DependencyProperty OffsetProperty = DependencyProperty.Register(
        "Offset",
        typeof(double),
        typeof(ScrollToOffsetBehavior),
        new PropertyMetadata(0.0));

    public double Offset
    {
        get { return (double)GetValue(OffsetProperty); }
        set { SetValue(OffsetProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        if (this.contentElement != null)
        {
            this.contentElement.SizeChanged -= contentElement_SizeChanged;
        }

        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
        }
    }

    void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        this.contentElement = this.AssociatedObject.Content as FrameworkElement;

        if (this.contentElement != null)
        {
            this.contentElement.SizeChanged += new SizeChangedEventHandler(contentElement_SizeChanged);
        }
    }

    void contentElement_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        this.AssociatedObject.ScrollToVerticalOffset(this.Offset);
    }
}

然后,您可以将此行为应用于XAML中的ScrollViewer(并指定偏移量0以滚动回顶部):

   <ScrollViewer>
        <i:Interaction.Behaviors>
            <local:ScrollToOffsetBehavior Offset="0"/>
        </i:Interaction.Behaviors>
        ...Scroll Viewer Content...
    </ScrollViewer>

这将假设您始终希望在内容大小更改时滚动到偏移量。这可能不是您正在寻找的,但它是使用行为在视图中完成此类事情的一个示例。