UWP FillRowViewPanel
最近有童鞋有这种需求,说实话我不知道这个Panel怎么起名字。
效果连接https://tuchong.com/tags/风光/
下面是我做成的效果,可以规定每个Row的Items个数
2个

3个

4个

代码在:GitHub
下面我来说一下我的思路
其实很早之前就写过这种可变大小的控件,但这次的跟这个需求有点变化,这个每一行个数一定,大小根据图片的大小进行填充。
微软默认的VariableSizedWrapGrid和Toolikt里面的StaggeredPanel都会导致ListView失去一些特性(虚拟化,增量加载)
之前做另一种。其实现在这个差不多。就是ListViewItem 就是每一行,那么每一行里面相当于一个水平的ListView。
我只需要做一个Panel来布局填充行就可以了。。垂直上面还是ListView自带的效果
除此之后,还需要一个数据源来把 一维的数据改为了 二维的(根据每一行的个数)
直接上代码:
FillRowViewSource这个类是把一个 一维的数据源改为了 二维的。主要方法是UpdateRowItems根据RowItemsCount把集合分割
private void UpdateRowItems()
{
if (sourceList == null)
{
return;
}
int i = ;
var rowItems = sourceList.Skip(i * RowItemsCount).Take(RowItemsCount);
while (rowItems != null && rowItems.Count() != )
{
var rowItemsCount = rowItems.Count();
var item = this.ElementAtOrDefault(i);
if (item == null)
{
item = new ObservableCollection<T>();
this.Insert(i, item);
} for (int j = ; j < rowItemsCount; j++)
{
var rowItem = rowItems.ElementAt(j);
var temp = item.ElementAtOrDefault(j);
if (temp==null || !temp.Equals(rowItem))
{
item.Insert(j, rowItem);
}
} while (item.Count > rowItemsCount)
{
item.RemoveAt(item.Count - );
}
i++;
rowItems = sourceList.Skip(i * RowItemsCount).Take(RowItemsCount);
} var rowCount = sourceList.Count / RowItemsCount + ;
while (this.Count > rowCount)
{
this.RemoveAt(this.Count - );
} }
FillRowViewPanel 最早的时候希望使用item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));方式来获得每个元素的大小,但是像Image这些控件不是开始就有大小的,需要等待图片加载完毕,而且每个Item都进行Measure的话。性能也不佳。
最后还是按照老控件的方式IResizable 写了个接口。绑定的数据源对象必须继承这个。你需要告诉我你的每个Item的大小尺寸。这样计算起来就方便多了而且有效多了
public class FillRowViewPanel : Panel
{
public int MinRowItemsCount
{
get { return (int)GetValue(MinRowItemsCountProperty); }
set { SetValue(MinRowItemsCountProperty, value); }
} // Using a DependencyProperty as the backing store for MinRowItemsCount. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinRowItemsCountProperty =
DependencyProperty.Register("MinRowItemsCount", typeof(int), typeof(FillRowViewPanel), new PropertyMetadata()); protected override Size MeasureOverride(Size availableSize)
{
var size = base.MeasureOverride(availableSize);
return size;
} protected override Size ArrangeOverride(Size finalSize)
{
double childrenWidth = ;
//double maxheight = double.MinValue;
foreach (var item in Children)
{
if (item is ContentControl cc && cc.Content is IResizable iResizable)
{
//item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var elementSize = iResizable;
var width = elementSize.Width * finalSize.Height / elementSize.Height;
//maxheight = Math.Max(elementSize.Height, maxheight);
childrenWidth += width;
}
} double ratio = childrenWidth / finalSize.Width;
double x = ;
var count = Children.Count;
foreach (var item in Children)
{
if (item is ContentControl cc && cc.Content is IResizable iResizable)
{
var elementSize = iResizable;
var width = elementSize.Width * finalSize.Height / elementSize.Height;
//if children count is less than MinRowItemsCount and chidren total width less than finalwidth
//it don't need to stretch children
if (count < MinRowItemsCount && ratio < )
{
//to nothing
}
else
{
width /= ratio;
} var rect = new Rect(x, , width, finalSize.Height);
item.Measure(new Size(rect.Width, finalSize.Height));
item.Arrange(rect);
x += width;
} }
return base.ArrangeOverride(finalSize);
}
}
在Sample页面
原理就是Listview的Item其实是个ListView。而做为Item的ListView的Panel是FillRowViewPanel
记住给FillRowViewPanel的高度进行设置。相当于每个元素的高度
<ct:PullToRefreshGrid RefreshThreshold="" PullToRefresh="PullToRefreshGrid_PullToRefresh">
<ListView x:Name="FillRowView" SizeChanged="FillRowView_SizeChanged">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value=""/>
<Setter Property="Padding" Value=""/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<ListView ScrollViewer.HorizontalScrollMode="Disabled" ItemsSource="{Binding}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value=""/>
<Setter Property="Padding" Value=""/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ct:FillRowViewPanel x:Name="fillRowViewPanel" MinRowItemsCount="" Height=""/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<!--<msct:ImageEx Margin="" IsCacheEnabled="True" Source="{Binding ImageUrl}" Stretch="Fill"/>-->
<Image Margin="" Source="{Binding ImageUrl}" Stretch="Fill"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ct:PullToRefreshGrid>
在整个ListViewSizechanged的时候我们再根据自己的需求调整RowItemsCount。
private void FillRowView_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (e.NewSize.Width < )
{
source.UpdateRowItemsCount();
}
else if (e.NewSize.Width >= && e.NewSize.Width < )
{
source.UpdateRowItemsCount();
}
else
{
source.UpdateRowItemsCount();
}
}
整个就差不多这样了。做的比较简单。一些东西也没有全部去考虑。比如SourceList_CollectionChanged的时候。只考虑了Reset这种方式。
算是比较针对这个需求做的东东吧,如果有其他需求。可以提出来。大家一起撸撸。
老规矩 开源有益:Github
UWP FillRowViewPanel的更多相关文章
- UWP 律师查询 MVVM
APP简介 律师查询是基于聚合数据的律师查询接口做的,这个接口目前处于停用状态,但是,由于我是之前申请的,所以,还可以用,应该是无法再申请了. 效果图 开发 一.HttpHelper 既然是请求接口的 ...
- 领域驱动和MVVM应用于UWP开发的一些思考
领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...
- UWP中实现自定义标题栏
UWP中实现自定义标题栏 0x00 起因 在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框.按钮之类的控件.搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章: http ...
- UWP中新加的数据绑定方式x:Bind分析总结
UWP中新加的数据绑定方式x:Bind分析总结 0x00 UWP中的x:Bind 由之前有过WPF开发经验,所以在学习UWP的时候直接省略了XAML.数据绑定等几个看着十分眼熟的主题.学习过程中倒是也 ...
- MVVM框架从WPF移植到UWP遇到的问题和解决方法
MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...
- UWP学习目录整理
UWP学习目录整理 0x00 可以忽略的废话 10月6号靠着半听半猜和文字直播的补充看完了微软的秋季新品发布会,信仰充值成功,对UWP的开发十分感兴趣,打算后面找时间学习一下.谁想到学习的欲望越来越强 ...
- UWP开发必备:常用数据列表控件汇总比较
今天是想通过实例将UWP开发常用的数据列表做汇总比较,作为以后项目开发参考.UWP开发必备知识点总结请参照[UWP开发必备以及常用知识点总结]. 本次主要讨论以下控件: GridView:用于显示数据 ...
- UWP开发必备以及常用知识点总结
一直在学UWP,一直在写Code,自己到达了什么水平?还有多少东西需要学习才能独挡一面?我想对刚接触UWP的开发者都有这种困惑,偶尔停下来总结分析一下还是很有收获的! 以下内容是自己开发中经常遇到的一 ...
- UWP开发之Mvvmlight实践九:基于MVVM的项目架构分享
在前几章介绍了不少MVVM以及Mvvmlight实例,那实际企业开发中将以那种架构开发比较好?怎样分层开发才能节省成本? 本文特别分享实际企业项目开发中使用过的项目架构,欢迎参照使用!有不好的地方欢迎 ...
随机推荐
- fastcgi vc6.0demo
#include <WinSock2.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") ty ...
- 【搜索】 Find The Multiple
#include<stdio.h> #include<stdlib.h> #include<string.h> bool found; void DFS(unsig ...
- 网络编程之基于tcp和udp的套接字
一 udp协议网络编程 DNS:将域名解析成ip地址 SOCK_DGRAM:数据报协议,也是udp协议 udp协议的网络编程的一些用法: recvfrom:接收消息,接收的时一个元组,元组里面的元 ...
- python学习之ansible api
Python API 2.0 从2.0的事情开始更复杂一些,但是你会得到更多离散和可读的类: #!/usr/bin/env python import json from collections im ...
- IntelliJ IDEA 2017版 spring-boot2.0.2 搭建 JPA springboot DataSource JPA 实体类浅谈
一.实体类分析 一般用到的实体类的类型有 String类型.Long类型.Integer类型.Double类型.Date类型.DateTime类型.Text类型.Boolean型等 1.String类 ...
- Python 之 filecmp
Python 之 filecmp 2017年7月12日 参考书籍:<Python自动化运维 ——技术与最佳实践> 作者:李天斯 1.什么是filecmp filecmp作为python的标 ...
- HDFS块文件和存放目录的关系
详情请参见DatanodeUtil.java中的函数idToBlockDir(File root, long blockId). 如果block文件没有放在正确的目录下,则DataNode会出现&qu ...
- winSockets编程(七)WSAAsyncSelect模式
占位## #include <WinSock2.h> #include <Windows.h> #include <StrSafe.h> #pragma comme ...
- 初识Android的ReactiveX
初识Android的ReactiveX 开发一个复杂一点的Android应用都会用到网络请求,交互和动画.这些都意味着 要写很多的回调嵌套.这样的代码也被称为callback hell(回调地狱).这 ...
- 20155326 2016-2017-2 《Java程序设计》第九周学习总结
20155326 2016-2017-2 <Java程序设计>第九周学习总结 教材学习内容总结 1.撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找. 2.JDBC目的 ...