UWP 下拉刷新控件(PullToRefreshControl)

最近项目里面有下拉刷新的需求,自己做了一个,效果还不错。

  <Style TargetType="local:PullToRefreshControl">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Grid>
                        <StackPanel VerticalAlignment="Center" Orientation="Horizontal" Visibility="{Binding IsReachThreshold,Converter={StaticResource InversedBooleanToVisibilityConverter}}">
                            <FontIcon FontSize="30"  FontFamily="Segoe UI Emoji" Glyph="" IsHitTestVisible="False"  VerticalAlignment="Bottom"/>
                            <TextBlock Margin="5,0,5,0" Text="下拉刷新" VerticalAlignment="Bottom"/>
                        </StackPanel>
                        <StackPanel VerticalAlignment="Center" Orientation="Horizontal" Visibility="{Binding IsReachThreshold, Converter={StaticResource BooleanToVisibilityConverter}}">
                            <FontIcon FontSize="30"   FontFamily="Segoe UI Emoji" Glyph="" IsHitTestVisible="False" VerticalAlignment="Bottom"/>
                            <TextBlock Margin="5,0,5,0" Text="释放立即刷新" VerticalAlignment="Bottom"/>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:PullToRefreshControl">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Margin="{TemplateBinding Margin}">
                        <ScrollViewer x:Name="ScrollViewer"
                                      VerticalScrollBarVisibility="Hidden">
                            <StackPanel>
                                <ContentControl x:Name="PanelHeader" ContentTemplate="{TemplateBinding HeaderTemplate}" HorizontalContentAlignment="Center" VerticalContentAlignment="Bottom" />
                                <ContentPresenter x:Name="PanelContent" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </StackPanel>
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 [TemplatePart(Name = PanelHeader, Type = typeof(ContentControl))]
    [TemplatePart(Name = PanelContent, Type = typeof(ContentPresenter))]
    [TemplatePart(Name = ScrollViewer, Type = typeof(ScrollViewer))]
    public class PullToRefreshControl:ContentControl
    {
        #region Fields
        private const string PanelHeader = "PanelHeader";
        private const string PanelContent = "PanelContent";
        private const string ScrollViewer = "ScrollViewer";
        private ContentControl _panelHeader;
        private ContentPresenter _panelContent;
        private ScrollViewer _scrollViewer;
        #endregion

        #region Property

        /// <summary>
        /// The threshold for release to refresh,defautl value is 2/5 of PullToRefreshPanel's height.
        /// </summary>
        public double RefreshThreshold
        {
            get { return (double)GetValue(RefreshThresholdProperty); }
            set { SetValue(RefreshThresholdProperty, value); }
        }

        // Using a DependencyProperty as the backing store for RefreshThreshold.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RefreshThresholdProperty =
            DependencyProperty.Register("RefreshThreshold", typeof(double), typeof(PullToRefreshControl), new PropertyMetadata(0.0,new PropertyChangedCallback(OnRefreshThresholdChanged)));

        private static void OnRefreshThresholdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var pullToRefreshControl = d as PullToRefreshControl;
            pullToRefreshControl.UpdateContentGrid();
        }

        /// <summary>
        /// occur when reach threshold.
        /// </summary>
        public event EventHandler PullToRefresh;

        public DataTemplate HeaderTemplate
        {
            get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderTemplateProperty =
            DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(PullToRefreshControl), new PropertyMetadata(null));

        public bool IsReachThreshold    
        {
            get { return (bool)GetValue(IsReachThresholdProperty); }
            set { SetValue(IsReachThresholdProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsReachThreshold.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsReachThresholdProperty =
            DependencyProperty.Register("IsReachThreshold", typeof(bool), typeof(PullToRefreshControl), new PropertyMetadata(false));


        #endregion

        protected override void OnApplyTemplate()
        {
            _panelHeader = GetTemplateChild(PanelHeader) as ContentControl;
            _panelHeader.DataContext = this;
            _panelContent = GetTemplateChild(PanelContent) as ContentPresenter;
            _scrollViewer = GetTemplateChild(ScrollViewer) as ScrollViewer;
            _scrollViewer.ViewChanged += _scrollViewer_ViewChanged;
            base.OnApplyTemplate();
        }

        private void _scrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
        {
            //Sometime we can't make it to 0.0.
            IsReachThreshold = _scrollViewer.VerticalOffset <= 5.0;
            if (e.IsIntermediate)
            {
                return;
            }

            if (IsReachThreshold)
            {
                if (PullToRefresh!=null)
                {
                    PullToRefresh(this, null);
                }
            }
            _panelHeader.Height = RefreshThreshold > _panelHeader.ActualHeight ? RefreshThreshold : _panelHeader.ActualHeight;
            this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                _scrollViewer.ChangeView(null, _panelHeader.Height, null);
            });

        }

        public PullToRefreshControl()
        {
            this.DefaultStyleKey = typeof(PullToRefreshControl);
            this.Loaded +=(s,e)=>
            {
                if (RefreshThreshold == 0.0)
                {
                    RefreshThreshold = this.ActualHeight * 2 / 5.0;
                }
                UpdateContentGrid();
            };
            this.SizeChanged += (s, e) =>
            {
                if (RefreshThreshold==0.0)
                {
                    RefreshThreshold = this.ActualHeight *2 / 5.0;
                }
                UpdateContentGrid();
            };
        }

        #region Method
        private void UpdateContentGrid()
        {
            if (_scrollViewer != null && _panelContent!=null && _panelHeader !=null)
            {
                _panelHeader.Height = RefreshThreshold > _panelHeader.ActualHeight? RefreshThreshold: _panelHeader.ActualHeight;
                this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                {
                    _scrollViewer.ChangeView(null, _panelHeader.Height, null, true);
                });
                _panelContent.Width = this.ActualWidth;
                _panelContent.Height = this.ActualHeight;
            }
        }
        #endregion
    }

 

posted @ 2016-01-11 13:21  法的空间  阅读(524)  评论(0编辑  收藏  举报