使用长列表选择器Windows Phone 8进行拉式刷新

本文关键字:刷新 Phone 列表 选择器 Windows | 更新日期: 2023-09-27 18:27:02

我目前正在使用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检测pull以刷新,但它有一些缺陷(使用鼠标输入、MOve和Leave),如:

    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>

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

使用长列表选择器Windows Phone 8进行拉式刷新

您可以通过ItemRealized事件并使用ListHeader(或从底部拖动的ListFooter)来实现这一点。在ItemRealized事件中,您检查该项是否是您的头对象。如果是,则加载更多项目。

来自Windows Phone开发人员博客

每当LongListSelector项获取要在屏幕上显示的UI容器时,就会引发ItemRealized事件。换句话说,每当项目进入当前视口上方或下方的UI缓冲区时,就会引发ItemRealized事件。事件参数属性ItemKind指示UI容器是ItemListHeaderGroupHeaderListFooter。使用属性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搜索示例

这并不完全是琐碎的,但其中一种方法是使用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;
    }

最后,您可以发现列表是否一直位于顶部:

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;
    }
}