滚动时将元素保持在视图中

时间:2013-08-24 23:46:58

标签: xaml windows-phone-8 scrollviewer

Simpel问题,我有一个包含scrollviewer的Windows手机页面,里面有imagetextblockrichtextbox

现在,当用户开始滚动时,我想在textblock滚动到页面外时将image保持在顶部。

因此效果是,用户开始向上滚动,所有内容向上滚动,当图像在页面外时,文本块保留在页面顶部,但richtextbox继续向上滚动。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

以下是达到此结果的方法:

首先,布局。我设置了一个网格,有两行。第一个是空的,当我们需要冻结它时将托管标题。第二行包含scrollviewer。

在scrollviewer中,我将控件放在网格中,但你可以使用任何适合你的容器。

<ScrollViewer Grid.Row="1"
                Margin="0"
                Padding="0"
                x:Name="ParentScroll"
                ManipulationMode="Control"
                MouseMove="ParentScroll_MouseMove">
    <Grid x:Name="ChildGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <Image Source="Picture.jpg" Grid.Row="0"/>
        <TextBlock Text="Header" Grid.Row="1" x:Name="TextHeader" />
        <RichTextBox Grid.Row="2" x:Name="RichText">
            <Paragraph>
                <Bold>RichTextBox</Bold>
                <!-- More stuff -->
            </Paragraph>
        </RichTextBox>
    </Grid>
</ScrollViewer>

我使用MouseMove事件来通知滚动事件。您还可以深入了解模板,提取ScrollBar控件,并订阅ValueChanged事件,如下所述:http://social.msdn.microsoft.com/Forums/wpapps/en-US/81fcd34e-6ec9-48d0-891e-c53a53344553/scrollviewer-synchronization

请注意,您需要将ManipulationMode设置为Control,否则控件的位置将无法以平滑的速率更新。我想这是由于一些内部优化。

在后面的代码中,我使用TransformToVisual方法计算控件与ScrollViewer的相对位置。通过这种方式,我可以知道标头何时不在视野范围内。如果是这样,我将其从子网格中删除,并将其放在父网格中的ScrollViewer之外。当RichTextBox的顶部不在视野范围内时,我将标题放回ScrollViewer中:

private void ParentScroll_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
    if (Grid.GetRow(this.TextHeader) == 1)
    {
        var generalTransform = TextHeader.TransformToVisual(ParentScroll);
        var childToParentCoordinates = generalTransform.Transform(new Point(0, 0));

        if (childToParentCoordinates.Y < 0)
        {
            this.ChildGrid.Children.Remove(this.TextHeader);
            this.ParentGrid.Children.Add(this.TextHeader);

            Grid.SetRow(this.TextHeader, 0);
        }
    }
    else
    {
        var generalTransform = RichText.TransformToVisual(ParentScroll);
        var childToParentCoordinates = generalTransform.Transform(new Point(0, 0));

        if (childToParentCoordinates.Y > 0)
        {
            this.ParentGrid.Children.Remove(this.TextHeader);
            this.ChildGrid.Children.Add(this.TextHeader);

            Grid.SetRow(this.TextHeader, 1);
        }
    }

可能有更少的hacky方法来达到相同的结果,但这个解决方案似乎在模拟器中顺利运行。

答案 1 :(得分:1)

我自己找到了一个可行的解决方案...我的blog here...上提供了完整的详细信息,它还包含了我在GitHub上的演示项目的链接。

诀窍是抓住VerticallScrollBar中的ScrollViewer并将ManipulationMode设置为Control以获得有关UI线程的足够反馈。 使用滚动条的滚动偏移信息,我们为要保持视图的特定ui元素设置动画。