这样做的AutoScroll与ScrollViewer.ScrollToEnd()只在调试时,事件处理过于简单工作 [英] Doing AutoScroll with ScrollViewer.ScrollToEnd() only worked while debugging, event handler too simple

查看:2144
本文介绍了这样做的AutoScroll与ScrollViewer.ScrollToEnd()只在调试时,事件处理过于简单工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看着这一个更好的解决方案,自动滚动我觉得自己是那么巧找到一个简单的解决方案,但它只能在调试会话:

Looking at this solution for a better autoscroll I thought myself to be so clever to find an easier solution, but it works only in a debug session:

    private void scrollviewer_Messages_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        ScrollViewer sv = sender as ScrollViewer;
        if (sv.VerticalOffset == sv.ScrollableHeight)
        {
            sv.ScrollToEnd();//debug breakpoint
        }
        return;
    }



尽管在此的ScrollViewer,自动滚屏作品,底部添加内容的文本块文字停留在视图。当用户滚动向上,以及更多内容添加,底部熄灭来看,自动滚屏是关闭的,这是罚款。当用户滚动回到底部,ScrollToEnd()应该自动滚屏重新开启,但增加了更多的内容,底部仍滚动拿出来看。

While adding content to the textblock in this ScrollViewer, autoscroll works, the bottom of the text stays in view. When the user scrolls upwards, and more content is added, the bottom goes out of view, autoscroll is off, which is fine. When the user scrolls back to the bottom, ScrollToEnd() should turn autoscroll back on, but when more content is added, the bottom still scrolls out of view.

当我设置断点,我可以验证ScrollToEnd()确实调用。然后,在删除断点,并添加更多的内容后,自动滚屏再次工作。

When I set the breakpoint, I can verify that ScrollToEnd() is indeed called. Then, after removing the breakpoint, and adding more content, autoscroll works again.

我在视图模型按下一个按钮,使用代码,并绑定添加内容。所以我肯定是没有并发问题。有添加内容和手动滚动之间的时间。

I add content by pressing a button, with code in the ViewModel, and Binding. So I am sure there is no concurrency problem. There is much time between adding content and manual scrolling.

这我百思不得其解,但我很高兴我的简单的自动滚屏的解决方案。 ?这怎么能不工作

This really baffles me, while I was so happy with my simple autoscroll solution. How can this not work?

编辑:

我发现,自动滚动滚动回到底部后重新工作,但不知何故,也不是那么容易,真正见底。我需要移动滑块一路下跌,并单击滚动条的向下箭头。我现在实验替换我的代码 == 符号,让几个像素的区别。

I found out that autoscroll works again after scrolling back to the bottom, but somehow it is not so easy to really hit the bottom. I need to move the slider way down, AND click the down arrow of the scrollbar. I will now experiment with replacing the == sign in my code to allow a few pixels difference.

编辑

会这个问题可以通过以下事实的内容是一个多行文本串和TextWrap一个TextBlock引起的?

Would this problem be caused by the fact that the content is a TextBlock with a multi-line text string and TextWrap?

    <ScrollViewer Name="scrollviewer_Messages" DockPanel.Dock="Top" 
                  Height="100" Width="200"           
                  ScrollChanged="scrollviewer_Messages_ScrollChanged">
        <TextBlock Name="tb_Message"
               Margin="10" TextWrapping="Wrap"
               Text="{Binding Path=Messages}">
        </TextBlock>
    </ScrollViewer>






编辑:


edit:

问题走了,在事件处理程序更改公式:

The problem went away with changing the formula in the event handler to:

 sv.ScrollableHeight - sv.VerticalOffset < 20



我尝试已经与< 10 但pushpraj(请参阅下面的回答)让我试试较大的数字。目前还不清楚为什么这个工作,因为问题不在于 ScrollToEnd()不叫。

I experimented already with < 10 but pushpraj (see answer below) made me try larger numbers. Still unclear why this works, as the problem is not that ScrollToEnd() was not called.

有关解决方案:

< 20 不是必要的,因为它是有关小数。在一般情况下,两个实数从不相等,但在这里是不正确的。在双击偏移和高度时,滑块在年底真正平等的。号

The <20 is not needed because it is about fractional numbers. In general, two real numbers are never equal, but here that is not true. The double numbers for offset and height are really equal when the slider is at the end.

的问题是,显然, ScrollToEnd /底部()不同时与滑块滚动工作。而已。我把它叫做一个错误,但它也可能是一个功能:一是不应该改变滑块的当用户滑动,需要被控制的行为

The problem is that, apparently, ScrollToEnd/Bottom() does not work while scrolling with the slider. That's it. I would call it a bug, but it might as well be a 'feature': one should not change the behaviour of the slider while the user is sliding it and expecting to be in control.

解决方法是,首先我们滑块滑动到最后,使得偏移==高度。第二步是添加内容将增加高度,由于上述错误滑块将向上移动一点点,在我的案件约15分。这就提出了一个ScrollChanged事件和<的门槛; 20 是充裕,足以让 ScrollToBottom 的第二个电话。这两个步骤中发生的每次添加的内容。

The fix is that first we slide the slider to the end, making Offset == Height. Step two is that adding content will increase Height, due to above bug the slider will move up just a little, in my case about 15 points. This raises a ScrollChanged event and the threshold of <20 is ample enough to get a second call of ScrollToBottom. This step two happens each time content is added.

我前面提到的编辑单击向下按钮的工作原理类似。显然,ScrollToEnd工程向下按钮。

My earlier edit mentioning clicking the down button works similar. Apparently, ScrollToEnd works for the down button.

当然美中不足的是,一个错误是一个错误。当一次添加更多的内容,门槛可能无法工作,并自动滚屏可能会停止。

The catch of course is that a bug is a bug. When adding more content at once, the threshold may not work, and autoscroll might stop.

的最终解决方案,并不是这么简单,我希望的,但还不算复杂的,应该是一个在我的回答如下。

The ultimate solution, not as simple as I was hoping for, but still not too complex, should be the one in my answer below.

推荐答案

问题的原因是 ScrollToEnd ()无关与自动滚屏。这个调用只是滚动到最后,就是这样。通过将调用在事件处理程序会非常频繁滚动到结束,而是一个真正的自动滚屏,有必要确定谁触发事件:用户通过移动滑块,或者因为内容大小的变化移动滑块。相反,通过查看 ExtentHeight 忽略无用的事件中,该酒店目前用于确定谁或什么触发事件。

The cause of the problem is that ScrollToEnd() has nothing to do with autoscroll. This call just scrolls to the end and that is it. By putting the call in the event handler it will scroll pretty often to the end but for a true autoscroll it is necessary to determine who fired the event: the user by moving the slider, or the slider by moving because of change of content size. Instead of ignoring "useless" events by looking at ExtentHeight, this property is now used to determine the who or what fired the event.

这个解决方案节省了控制的变量自动滚屏位的状态。它甚至会更好,以继承到一个新的用户控件AutoScrollViewer。

This solution saves the state of the autoscroll bit in the tag of the control. It would even be nicer to subclass to a new usercontrol AutoScrollViewer.

毕竟,这个解决方案在上面的问题提到是不是比以前的解决方案相比,简单, ,它仅仅是一个变化,但它是(希望)更精确的

After all, this solution is not much "simpler" than the previous solutions as mentioned above in the question, it is merely a variation, but it is (hopefully) more accurate.

    /// <summary>
    /// If the scrollviewer is at the bottom, keep the bottom in view.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void scrollviewer_Messages_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        ScrollViewer sv = sender as ScrollViewer;
        bool AutoScrollToEnd = true;
        if (sv.Tag != null)
        {
            AutoScrollToEnd = (bool)sv.Tag;
        }
        if (e.ExtentHeightChange == 0)// user scroll
        {                
            AutoScrollToEnd = sv.ScrollableHeight == sv.VerticalOffset;
        }
        else// content change
        {                
            if (AutoScrollToEnd)
            {
                sv.ScrollToEnd();
            }
        }
        sv.Tag = AutoScrollToEnd;
        return;
    }

这篇关于这样做的AutoScroll与ScrollViewer.ScrollToEnd()只在调试时,事件处理过于简单工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆