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

时间:2013-08-09 03:28:31

标签: c# xaml windows-phone-8 windows-phone

我目前正在使用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-to-refresh,但它有一些缺陷(使用Mouse Enter,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>

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

2 个答案:

答案 0 :(得分:1)

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

来自Windows Phone Dev Blog

  

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

     

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

来自他们提供的Twitter sample

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 Search sample

答案 1 :(得分: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;
    }

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

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