UPW ListView 下拉刷新2种方法
UPW ListView 下拉刷新方法-通过访问ListView内部的ScrollViewer控件,来监听ViewChanged事件。(直接测试有效)
访问ListView内部的ScrollViewer,必定离不开VisualTreeHelper类中的以下两个方法:
public static DependencyObject GetChild(DependencyObject reference, System.Int32 childIndex);
public static System.Int32 GetChildrenCount(DependencyObject reference);
可以将这两个方法进一步组合得到:
static T FindFirstChild<T>(FrameworkElement element) where T : FrameworkElement
{
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
var children = new FrameworkElement[childrenCount];
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
children[i] = child;
if (child is T)
return (T)child;
}
for (int i = 0; i < childrenCount; i++)
if (children[i] != null)
{
var subChild = FindFirstChild<T>(children[i]);
if (subChild != null)
return subChild;
}
return null;
}
该方法通过递归来遍历FrameworkElement内部的元素,并返回第一个符合类型的元素。ListViewEx的第一个扩展如下:
自定义一个类ListViewEx 继承自ListView,并且实现INotifyPropertyChanged 接口
public class ListViewEx : ListView, INotifyPropertyChanged
{
private ScrollViewer _scrollViewer;
public event EventHandler LoadHistoryEvent;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnProperyChanged(string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public ListViewEx()
{
this.Loaded += ListViewEx_Loaded;
this.Unloaded += ListViewEx_Unloaded;
}
private void ListViewEx_Unloaded(object sender, RoutedEventArgs e)
{
this.Unloaded -= ListViewEx_Unloaded;
if (_scrollViewer != null)
{
_scrollViewer.ViewChanged -= Sv_ViewChanged;
}
}
private void ListViewEx_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
this.Loaded -= ListViewEx_Loaded;
_scrollViewer = FindFirstChild<ScrollViewer>(this);
if (_scrollViewer != null)
{
_scrollViewer.ViewChanged += Sv_ViewChanged;
}
}
private async void Sv_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (e.IsIntermediate == false && _scrollViewer.VerticalOffset >= _scrollViewer.ScrollableHeight-10 && _scrollViewer.VerticalOffset <= _scrollViewer.ScrollableHeight)
{
// _scrollViewer.ChangeView(null, 50, null);
// await Task.Delay(10);
LoadHistoryEvent?.Invoke(this, EventArgs.Empty);
}
}
static T FindFirstChild<T>(FrameworkElement element) where T : FrameworkElement
{
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
var children = new FrameworkElement[childrenCount];
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
children[i] = child;
if (child is T)
return (T)child;
}
for (int i = 0; i < childrenCount; i++)
if (children[i] != null)
{
var subChild = FindFirstChild<T>(children[i]);
if (subChild != null)
return subChild;
}
return null;
}
}
XAML UI 大代码:
<local:ListViewEx x:Name="listView2" LoadHistoryEvent="listView2_LoadHistoryEvent" ItemTemplateSelector="{StaticResource mtSelector}" ItemsSource="{Binding}" Background="WhiteSmoke" SelectionMode="Single">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid ItemWidth ="444" MaximumRowsOrColumns="8" Orientation="Horizontal"></ItemsWrapGrid>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</local:ListViewEx>
public MainPage()
{
this.InitializeComponent();
listView. DataContext = listData ;
}
bool isLoading;
ObservableCollection<data> listData = new ObservableCollection<data>();
private void listView2_LoadHistoryEvent(object sender, EventArgs e)
{
bindData();
}
void bindData()
{
if (isLoading) return;
for (int i = 1; i < 12; i++)
{
listData.Add(new data() { Id = 1, title = "ttttt1", picUrl = "http://www.songshizhao.com/editor/attached/image/20170416/123.jpg20170416115527_9528.jpg" });
listData.Add(new data() { Id = 2, title = "ttttt1", picUrl = "http://www.songshizhao.com/editor/attached/image/20170416/123.jpg20170416115527_9528.jpg" });
}
listView2.ItemsSource = listData;
isLoading = false;
}
///数据实体类
public class data {
public string title { get; set; }
public string picUrl { get; set; }
public int Id { get; set; }
}
----------------------
下面是其他候选方法(没有见过直接测试):
.通过ListView控件的ContainerContentChanging方法。该方法在列表项被实例化时触发,在列表项最后一个项目实例化的时候触发刷新数据逻辑就可以实现下拉加载了。
代码如下:
//list_ContainerContentChanging在列表项被实例化是触发。
private void list_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (!isLoading)
{
if (args.ItemIndex == list.Items.Count - 1)
{
isLoading = true;
//加载需要加载的内容
Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
int sum = Items.Count;
for (int i = sum; i < sum+50; i++)
{
Items.Add(new Item(i.ToString()));
}
isLoading = false;
});
});
}
}
}
2.通过获取ListVeiw的ScrollViewer 和 ScrollBar,监控ScrollBar的ValueChange事件,在ScroolBar滚动到最底部时触发刷新数据逻辑。
代码如下:
//在ListView加载后获取Scrollview和ScrollBar,否则可能会获取不到。
private void list_Loaded(object sender, RoutedEventArgs e)
{
sv = FindVisualChildByName<ScrollViewer>(list, "ScrollViewer");
sb = FindVisualChildByName<ScrollBar>(sv, "VerticalScrollBar");
sb.ValueChanged += Sb_ValueChanged;
}
private void Sb_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
if(e.NewValue > e.OldValue && e.NewValue >= sb.Maximum)
{
if (!isLoading)
{
isLoading = true;
//加载需要加载的内容。
Task.Factory.StartNew(async () =>
{
await Task.Delay(1000);
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
int sum = Items.Count;
for (int i = sum; i < sum+50; i++)
{
Items.Add(new Item(i.ToString()));
}
isLoading = false;
});
});
}
}
}
fffffffffffffffff
test red font.