2010-01-26 58 views
0

enter code here我有一个ScrollViewer中在每当我背后叫ScrollToVerticalOffset方法从代码中无垂直滚动的Silverlight。的Silverlight的ScrollViewer进行滚动

基本上,我有我的视图(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); 
     } 
    } 
} 
+0

我不明白为什么这种解决方案无法正常工作......您是否试图将视口固定到元素面板的顶部或底部?你确定每次添加新元素时都会调用OnBindableOffsetChanged?如果你只是每次将视图模型属性设置为0.0(滚动到顶部),我可以看到它为什么只能在第一次被调用,而不会再被调用。 – 2010-01-27 03:34:29

回答

0

这种做法在我看来有点古怪,因为我觉得既是一个ScrollViewer中和VerticalScrollOffset作为应具有极小的(或没有)做的一个视图模型“视图”实体。看起来这可能会迫使MVVM太多,并创建附加的依赖项属性的额外工作,并基本上试图保持绑定的Offset ViewModel属性与ScrollViewer的只读VerticalScrollOffset同步。

我并不确切肯定您试图什么来实现的,但它听起来就像你正试图滚动到当一些动态元素添加到您的ScrollViewer的底层面板指定偏移量。就我个人而言,我只想在视图中用一点代码处理这种行为,而忘记将它绑定到ViewModel。

在Silverlight 3中执行此类事情的一个非常好的方法是使用Blend行为。你用C#编写了一些行为代码,然后可以声明地将它附加到XAML中的元素。这可以保证它可以重用,并且不会出现代码隐藏。您的项目将不得不引用作为Blend SKD一部分的System.Windows.Interactivity DLL。

这里有一个简单的混合行为的一个简单的例子,你可以添加到的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); 
    } 
} 

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

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

这会假设你总是希望滚动到偏移每当内容大小的变化。这可能不是您正在寻找的内容,但它是使用行为在视图中如何完成这样的事情的一个示例。