使用ListBox進行資料綁定的時候預設都是豎向的排版方式,意思就是一個Item會占用一行的位置,豎向地并排下去。當我們使用ListBox時,使用橫向排版的時候該怎麼辦呢?也就是說要在一行的位置上放兩個或者兩個以上的Item。通常的解決方法,我們會使用toolkit控件裡面的WrapPanel排版。
例如:
<ListBox Name="StackPanelListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Height="110" Width="110"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel></toolkit:WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
通過設定ListBox的ItemsPanel屬性的模闆為WrapPanel控件的排版方式就會自動地根據Item的寬度大小并排地排在一行上,當排滿了一行的時候就會繼續排列在下面的一行上,如此類推不斷地排下去,就實作了橫向的資料綁定排版。但是這種方式有一個很緻命的性能缺陷,因為會一次性地把所有的Item都初始化完成并展現在UI上,當Item的數量很多的時候就需要耗費很長的響應時間,導緻使用者體驗很差,也會影響程式的性能。
下面使用一種新的方法來解決WrapPanel橫向排版引發的性能問題。
當我們使用ListBox預設的排版方式綁定資料時,它不會一次性地将所有的Item全部初始化完畢并展示在UI上,它會根據螢幕的位置初始化部分的Item,這部分Item是在你看到的螢幕上的Item和螢幕上下一屏的Item。那就利用這種原理來設計一個橫向排版的ListBox資料綁定。
實作的方法是先将Item進行分組,一行要排列多少個Item那麼就一組有多少個Item,分好組之後再把組作為一個新的Item建構一個新的資料綁定源。假如我們需要綁定的資料源的Item有200個,那麼我們一行要排4個Item就要分50組,這時候構成的新的資料綁定源就是50行,在整體的ListBox裡面是豎向排版,在一行的資料裡面是橫向排版,這就實作了跟WrapPanel的自動排版一樣的綁定效果了,但是性能卻比WrapPanel的自動排版要好很多。
執行個體:
Item.cs 資料源的Item
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Media;
using System.Threading;
namespace GridListDemo
{
public class Item : INotifyPropertyChanged
{
private string _name;
public string Name
{
get
{
return this._name;
}
set
if (this._name != value)
{
this._name = value;
RaisePropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string info)
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs(info));
}
}
GridDataRow.cs 組的資料源集合
using System.Collections;
using System.Reflection;
public class GridDataRow<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable
private IList<T> _items;//所有的item集合
private int _offset;//偏移量 即 前面的item數量
private int _rowItemCount;//行數
public GridDataRow(IList<T> itemsList, int offset, int rowItemCount)
this._items = itemsList;
this._offset = offset;
this._rowItemCount = rowItemCount;
public void Add(T item)
throw new NotImplementedException();
public void Clear()
public bool Contains(T item)
public void CopyTo(T[] array, int arrayIndex)
public IEnumerator<T> GetEnumerator()
public int IndexOf(T item)
public void Insert(int index, T item)
public bool Remove(T item)
public void RemoveAt(int index)
IEnumerator IEnumerable.GetEnumerator()
public int Count
//取行數和剩下的條數的最小的一個
int num = this._items.Count - this._offset;
return Math.Min(this._rowItemCount, num);
public bool IsReadOnly
return true;
public T this[int index]
return this._items[this._offset + index];
throw new NotImplementedException();
RowCollection.cs 行的綁定資料源的集合
using System.Collections.Specialized;
using System.Windows;
public class RowCollection<T> : IList<GridDataRow<T>>, IList where T : new()
private IList<T> _itemsCollection;
private int _rowItemCount;//一行的數量
public RowCollection(IList<T> itemsCollection, int rowItemCount)
this._itemsCollection = itemsCollection;
public void Add(GridDataRow<T> item)
public int Add(object value)
public bool Contains(object value)
public bool Contains(GridDataRow<T> item)
public void CopyTo(Array array, int index)
public void CopyTo(GridDataRow<T>[] array, int arrayIndex)
public IEnumerator<GridDataRow<T>> GetEnumerator()
public int IndexOf(object value)
return -1;
public int IndexOf(GridDataRow<T> item)
public void Insert(int index, GridDataRow<T> item)
public void Insert(int index, object value)
public void Remove(object value)
public bool Remove(GridDataRow<T> item)
//總數處于一行的數量等于清單的行數
return Convert.ToInt32(Math.Ceiling((double)(((double)this._itemsCollection.Count) / ((double)this._rowItemCount))));
public bool IsFixedSize
return false;
public bool IsSynchronized
public GridDataRow<T> this[int index]
return new GridDataRow<T>(this._itemsCollection, index * this._rowItemCount, this._rowItemCount);
public object SyncRoot
return this;
object IList.this[int index]
return this[index];
MyGridRow.cs 自定義的組控件
using System.Windows.Controls;
using System.Windows.Data;
/// <summary>
/// 橫向排版,繼承Canvas控件
/// </summary>
public class MyGridRow : Canvas
//定義ItemsSource屬性
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IList<Item>), typeof(MyGridRow), new PropertyMetadata(new PropertyChangedCallback(MyGridRow.OnItemsSourceChanged)));
/// <summary>
/// 初始化GridRow控件
/// </summary>
private void ApplyRaw()
if ((this.ItemsSource == null) || (this.ItemsSource.Count != base.Children.Count))
base.Children.Clear();
if (this.ItemsSource != null)
for (int i = 0; i < this.ItemsSource.Count<Item>(); i++)
{
Item item = this.ItemsSource[i];
TextBlock tb = new TextBlock
{
DataContext = item,
Width = 80.0,
Height = 80.0
};
Binding binding = new Binding("Name")
FallbackValue = null
BindingOperations.SetBinding(tb, TextBlock.TextProperty, binding);
//添加目标到Canvas控件裡面
base.Children.Add(tb);
Canvas.SetLeft(tb, (double)(i * 0x72));
}
else
for (int j = 0; j < this.ItemsSource.Count<Item>(); j++)
Item item2 = this.ItemsSource[j];
TextBlock tb2 = (TextBlock)base.Children[j];
tb2.Text = item2.Name;
/// ItemsSource改變事件
/// <param name="d"></param>
/// <param name="e"></param>
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
(d as MyGridRow).ApplyRaw();
//ItemsSource屬性
public IList<Item> ItemsSource
return (IList<Item>)base.GetValue(ItemsSourceProperty);
base.SetValue(ItemsSourceProperty, value);
在頁面中實作
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="GridViewTemplate">
<myControl:MyGridRow ItemsSource="{Binding}" Height="114" Width="480" />
</phone:PhoneApplicationPage.Resources>
.......
<ListBox Name="GridItemsListBox" HorizontalAlignment="Left"
ItemTemplate="{StaticResource GridViewTemplate}" />
List<Item> source = new List<Item>();
for (int i = 0; i < 200; i++)
source.Add(new Item { Name = "name" + i });
this.GridItemsListBox.ItemsSource = new RowCollection<Item>(source, 4);
運作的效果
<a href="http://blog.51cto.com/attachment/201212/155106775.png" target="_blank"></a>
本文轉自linzheng 51CTO部落格,原文連結:http://blog.51cto.com/linzheng/1078356