标签:control spro rop 一个 enc argument lin efault web
原文:WPF下制作的简单瀑布流效果
最近又在搞点小东西,美化界面的时候发现瀑布流效果比较不错.顺便就搬到了WPF,下面是界面
我对WEB前端不熟,JS和CSS怎么实现的,我没去研究过,这里就说下WPF的实现思路,相当简单.
1.最重要的就是每个子项的顺序填充,我是把界面看做N列,然后在每列里依次加载子项.最后结果就是,界面放一个Uniform,设置Columns,再添加几个ItemsControl.
2.添加Item的时候,判断每个ItemsControl的实际高度,把子项添加到最小的那个ItemsControl,这样避免了某一列拉得很长.
3.再做一层封装,就变成了一个支持Binding的WaterfallControl.
这里上几段控件的源码,供参考:
1.WaterfallControl.cs
1 [TemplatePart(Name = "grdRoot", Type = typeof(UniformGrid))]
2 public class WaterfallControl : ItemsControl
3 {
4 private UniformGrid grdRoot;
5
6 private List itemsContorls;
7
8 public int Columns
9 {
10 get { return (int)GetValue(ColumnsProperty); }
11 set { SetValue(ColumnsProperty, value); }
12 }
13
14 // Using a DependencyProperty as the backing store for Columns. This enables animation, styling, binding, etc...
15 public static readonly DependencyProperty ColumnsProperty =
16 DependencyProperty.Register("Columns", typeof(int), typeof(WaterfallControl), new PropertyMetadata(3, OnColumnsChanged));
17
18 private static void OnColumnsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
19 {
20 int columns = (int)e.NewValue;
21 if (columns 1)
22 {
23 throw new ArgumentOutOfRangeException("Columns");
24 }
25 var control = sender as WaterfallControl;
26 control.Columns = columns;
27 control.InitPanel();
28 }
29
30 public WaterfallControl()
31 {
32 this.Loaded += WaterfallControl_Loaded;
33 this.itemsContorls = new List();
34 }
35
36 void WaterfallControl_Loaded(object sender, RoutedEventArgs e)
37 {
38 this.InitPanel();
39 }
40
41 private void InitPanel()
42 {
43 if (!this.IsLoaded)
44 {
45 return;
46 }
47
48 grdRoot.Children.Clear();
49 itemsContorls.Clear();
50 for (var i = 0; i this.Columns; i++)
51 {
52 var ic = new ItemsControl();
53 ic.ItemTemplate = this.ItemTemplate;
54 ic.VerticalAlignment = System.Windows.VerticalAlignment.Top;
55 grdRoot.Children.Add(ic);
56 itemsContorls.Add(ic);
57 }
58
59 if (this.ItemsSource != null)
60 {
61 var enumerator = this.ItemsSource.GetEnumerator();
62 while (enumerator.MoveNext())
63 {
64 this.AddChild(enumerator.Current);
65 }
66 }
67 }
68
69 public override void OnApplyTemplate()
70 {
71 base.OnApplyTemplate();
72 grdRoot = (UniformGrid)this.GetTemplateChild("grdRoot");
73 }
74
75 protected override void AddChild(object value)
76 {
77 var ic = itemsContorls.OrderBy(t => t.ActualHeight).FirstOrDefault();
78 ic.Items.Add(value);
79 ic.UpdateLayout();
80 }
81
82 protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
83 {
84 if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Remove)
85 {
86 var enumerator = e.NewItems.GetEnumerator();
87 while (enumerator.MoveNext())
88 {
89 if (e.Action == NotifyCollectionChangedAction.Add)
90 {
91 this.AddChild(enumerator.Current);
92 }
93 else
94 {
95 foreach (var ic in this.itemsContorls)
96 {
97 ic.Items.Remove(enumerator.Current);
98 }
99 }
100 }
101 }
102 }
103 }
View Code
2.WaterfallControl的样式
Style TargetType="controls:WaterfallControl">
Setter Property="Template">
Setter.Value>
ControlTemplate TargetType="controls:WaterfallControl">
ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
UniformGrid Name="grdRoot" Columns="{TemplateBinding Columns}">
UniformGrid>
ScrollViewer>
ControlTemplate>
Setter.Value>
Setter>
Style>
View Code
3.调用
WaterfallControl继承自ItemsControl,所以和ItemsControl的使用没有区别,只需要额外指定一个Columns即可.
可能遇到的问题:
1.遇到图片不能直接计算高度,可能导致某列很长.可以用扩展属性给图片指定一个初始占位高度.
2.遇到界面大小变化,列数是不是应该动态变化,这个要实现也简单,监视下Window.SizeChanged,然后改变Columns就行了.
3.我直接把ScrollViewer放到WaterfallControl的模板里了,建议抽出来,监视下滚动事件,实现滚动到底加载数据.
4.不知道是否有更简单明了的方法.
WPF下制作的简单瀑布流效果
标签:control spro rop 一个 enc argument lin efault web
原文地址:https://www.cnblogs.com/lonelyxmas/p/10640039.html