1

我目前正在使用 Windows Phone 8 应用程序并遇到长列表选择器(LLS)的一些问题。列表框通过使用 TranslateY 值来做到这一点:

 UIElement scrollContent = (UIElement)this.targetScrollViewer.Content;
 CompositeTransform ct = scrollContent.RenderTransform as CompositeTransform;
 //ct.TranslateY: I need this value in Viewport's LLS to detect exactly the distance moving from the TOP

我正在尝试使用 LLS 检测拉动刷新,但它有一些缺陷(使用鼠标输入、移动和离开):

    double manipulationStart = 0;
    double manipulationEnd = 0;

    void targetLLS_MouseEnter(object sender, MouseEventArgs e)
    {
        if (!this.IsRefreshing)
        {
            var pos = e.GetPosition(null);
            manipulationStart = pos.Y;
            IsMoving = false;
        }
    }

    private void targetLLS_MouseMove(object sender, MouseEventArgs e)
    {
        if (!this.IsRefreshing)
        {
            var pos = e.GetPosition(null);

            manipulationEnd = pos.Y;
            IsMoving = true;

            double TranslateY = manipulationEnd - manipulationStart;

            if (TranslateY > this.PullThreshold)
            {
                this.PullDistance = 100;
                this.PullFraction = 1.0;
                activityState = PullDownToRefreshPanel.ReadyToReleaseVisualState;
            }
            else if (TranslateY > 0)
            {
                this.PullDistance = 100;
                double threshold = this.PullThreshold;
                this.PullFraction = 1;// threshold == 0.0 ? 1.0 : Math.Min(1.0, TranslateY / threshold);
                activityState = PullDownToRefreshPanel.PullingDownVisualState;
            }
            else
            {
                this.PullDistance = 0;
                this.PullFraction = 0;
                activityState = PullDownToRefreshPanel.InactiveVisualState;
            }

            VisualStateManager.GoToState(this, activityState, false);
        }
    }

    bool IsMoving = false;
    void targetLLS_MouseLeave(object sender, MouseEventArgs e)
    {
        if (!this.IsRefreshing && IsMoving)
        {
            double TranslateY = manipulationEnd - manipulationStart;
            EventHandler handler = this.RefreshRequested;

            if (this.targetLLS.IsAtTop()
                && (activityState == PullDownToRefreshPanel.ReadyToReleaseVisualState))// TranslateY >= this.PullThreshold
            {
                if (handler != null)
                {
                    IsRefreshing = true;
                    handler(this, EventArgs.Empty);
                }
            }

            IsMoving = false;
        }

        PullDistance = 0;
        PullFraction = 0;
        manipulationStart = 0;
        manipulationEnd = 0;
        activityState = PullDownToRefreshPanel.InactiveVisualState;
        //VisualStateManager.GoToState(this, activityState, false);
    }

我该如何使用以下模板:

 <Style x:Key="ViewportControlStyle" TargetType="ViewportControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ViewportControl">
                <ContentPresenter x:Name="ContentElement" Cursor="{TemplateBinding Cursor}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="LongListSelectorNormalStyle" TargetType="phone:LongListSelector">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="phone:LongListSelector">
                <Grid Background="{TemplateBinding Background}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="ScrollStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="00:00:00.5"/>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="Scrolling">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="VerticalScrollBar"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="NotScrolling"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid Margin="{TemplateBinding Padding}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <ViewportControl x:Name="ViewportControl" HorizontalContentAlignment="Stretch" VerticalAlignment="Top" Style="{StaticResource ViewportControlStyle}"/>
                        <ScrollBar x:Name="VerticalScrollBar" Grid.Column="0" Margin="4,0,4,0" Opacity="0" Orientation="Vertical" HorizontalAlignment="Right"/>
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我的项目需要实现拉功能,所以请帮助我。谢谢阅读!

4

2 回答 2

1

您可以使用ItemRealized事件并使用ListHeader(或ListFooter从底部拉出)来完成此操作。在 ItemRealized 事件中,您检查该项目是否是您的标题对象。如果是则加载更多项目。

来自Windows Phone 开发博客

每次 LongListSelector 项获取要在屏幕上显示的 UI 容器时,都会引发 ItemRealized 事件。换句话说,每次项目进入当前视口上方或下方的 UI 缓冲区时,都会引发ItemRealized事件。事件参数属性ItemKind指示 UI 容器是ItemListHeaderGroupHeader还是ListFooter。使用属性Container.Content,您可以获得与已实现的 UI 容器关联的实际对象。这样您就可以监视 UI 容器缓冲区中的对象。

请注意此示例中的应用程序代码如何包含私有变量_offsetKnob。这有助于根据项目模板的重量或发送数据的服务的响应速度来帮助确定何时加载更多项目,从而微调 LongListSelector 滚动体验。

来自他们提供的Twitter 样本

void resultList_ItemRealized(object sender, ItemRealizationEventArgs e)
{
    if (!_viewModel.IsLoading && resultList.ItemsSource != null && resultList.ItemsSource.Count >= _offsetKnob)
    {
        if (e.ItemKind == LongListSelectorItemKind.Item)
        {
            if ((e.Container.Content as TwitterSearchResult).Equals(resultList.ItemsSource[resultList.ItemsSource.Count - _offsetKnob]))
            {
                _viewModel.LoadPage(_searchTerm, _pageNumber++);
            }
        }
    }
}

下载完整的Twitter 搜索示例

于 2013-08-09T16:57:32.130 回答
0

这并非完全无关紧要,但一种方法是使用 GestureService

        this.gestureListener = GestureService.GetGestureListener(containerPage);
        this.gestureListener.DragStarted += gestureListener_DragStarted;
        this.gestureListener.DragCompleted += gestureListener_DragCompleted;
        this.gestureListener.DragDelta += gestureListener_DragDelta;

但是,它有一些错误。例如, DragCompleted 并不总是被引发,因此您需要使用 ManipulationCompleted 事件仔细检查,这似乎更可靠。

        containerPage.ManipulationStarted += delegate { this.manipulationInProgress = true; };
        containerPage.ManipulationCompleted += delegate
        { 
            this.manipulationInProgress = false;
            PerformDragComplete(); 
        };

另一个问题是 DragDelta 偶尔会报告错误的坐标。所以你需要这样的修复:

    Point refPosition = e.GetPosition(null);
    if (refPosition.X == 0 && refPosition.Y == 0)
    {
        Tracer.WriteLine("Skipping buggy event");
        return;
    }

最后,您可以找到 list 是否一直位于顶部:

public double VerticalOffset
{
    get
    {
        ViewportControl viewportControl = this.FindChildByName("ViewportControl") as ViewportControl;
        if (viewportControl != null)
        {
            Tracer.WriteLine("ViewPort.Bounds.Top=" + viewportControl.Bounds.Top +  " ViewPort.Top=" + viewportControl.Viewport.Top.ToString() + " State=" + this.ManipulationState);
            return viewportControl.Bounds.Top - viewportControl.Viewport.Top;
        }
        return double.NaN;
    }
}
于 2013-11-29T20:00:19.863 回答