且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Windows Phone 7 如何实现高效率的横向排版ListBox

更新时间:2022-09-26 11:28:49

使用ListBox进行数据绑定的时候默认都是竖向的排版方式,意思就是一个Item会占用一行的位置,竖向地并排下去。当我们使用ListBox时,使用横向排版的时候该怎么办呢?也就是说要在一行的位置上放两个或者两个以上的Item。通常的解决方法,我们会使用toolkit控件里面的WrapPanel排版。

例如:

 


  1. <ListBox Name="StackPanelListBox"> 
  2.     <ListBox.ItemTemplate> 
  3.         <DataTemplate> 
  4.                 <TextBlock Text="{Binding Name}" Height="110" Width="110"></TextBlock> 
  5.         </DataTemplate> 
  6.     </ListBox.ItemTemplate> 
  7.     <ListBox.ItemsPanel> 
  8.         <ItemsPanelTemplate> 
  9.             <toolkit:WrapPanel></toolkit:WrapPanel> 
  10.         </ItemsPanelTemplate> 
  11.     </ListBox.ItemsPanel> 
  12. </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

 


  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ComponentModel;  
  6. using System.Windows.Media;  
  7. using System.Threading;  
  8.  
  9. namespace GridListDemo  
  10. {  
  11.     public class Item : INotifyPropertyChanged  
  12.     {  
  13.         private string _name;  
  14.  
  15.         public string Name  
  16.         {  
  17.             get  
  18.             {  
  19.                 return this._name;  
  20.             }  
  21.             set  
  22.             {  
  23.                 if (this._name != value)  
  24.                 {  
  25.                     this._name = value;  
  26.                     RaisePropertyChanged("Name");  
  27.                 }  
  28.             }  
  29.         }  
  30.  
  31.         public event PropertyChangedEventHandler PropertyChanged;  
  32.  
  33.         public void RaisePropertyChanged(string info)  
  34.         {  
  35.             PropertyChangedEventHandler propertyChanged = this.PropertyChanged;  
  36.             if (propertyChanged != null)  
  37.             {  
  38.                 propertyChanged(this, new PropertyChangedEventArgs(info));  
  39.             }  
  40.         }  
  41.     }  

GridDataRow.cs 组的数据源集合

 


  1. using System;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4. using System.Reflection;  
  5.  
  6. namespace GridListDemo  
  7. {  
  8.  
  9.     public class GridDataRow<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable  
  10.     {  
  11.         private IList<T> _items;//所有的item集合  
  12.         private int _offset;//偏移量 即 前面的item数量  
  13.         private int _rowItemCount;//行数  
  14.  
  15.         public GridDataRow(IList<T> itemsList, int offset, int rowItemCount)  
  16.         {  
  17.             this._items = itemsList;  
  18.             this._offset = offset;  
  19.             this._rowItemCount = rowItemCount;  
  20.         }  
  21.  
  22.         public void Add(T item)  
  23.         {  
  24.             throw new NotImplementedException();  
  25.         }  
  26.  
  27.         public void Clear()  
  28.         {  
  29.             throw new NotImplementedException();  
  30.         }  
  31.  
  32.         public bool Contains(T item)  
  33.         {  
  34.             throw new NotImplementedException();  
  35.         }  
  36.  
  37.         public void CopyTo(T[] array, int arrayIndex)  
  38.         {  
  39.             throw new NotImplementedException();  
  40.         }  
  41.  
  42.         public IEnumerator<T> GetEnumerator()  
  43.         {  
  44.             throw new NotImplementedException();  
  45.         }  
  46.  
  47.         public int IndexOf(T item)  
  48.         {  
  49.             throw new NotImplementedException();  
  50.         }  
  51.  
  52.         public void Insert(int index, T item)  
  53.         {  
  54.             throw new NotImplementedException();  
  55.         }  
  56.  
  57.         public bool Remove(T item)  
  58.         {  
  59.             throw new NotImplementedException();  
  60.         }  
  61.  
  62.         public void RemoveAt(int index)  
  63.         {  
  64.             throw new NotImplementedException();  
  65.         }  
  66.  
  67.         IEnumerator IEnumerable.GetEnumerator()  
  68.         {  
  69.             throw new NotImplementedException();  
  70.         }  
  71.  
  72.         public int Count  
  73.         {  
  74.             get  
  75.             {  
  76.                 //取行数和剩下的条数的最小的一个  
  77.                 int num = this._items.Count - this._offset;  
  78.                 return Math.Min(this._rowItemCount, num);  
  79.             }  
  80.         }  
  81.  
  82.         public bool IsReadOnly  
  83.         {  
  84.             get  
  85.             {  
  86.                 return true;  
  87.             }  
  88.         }  
  89.  
  90.         public T this[int index]  
  91.         {  
  92.             get  
  93.             {  
  94.                 return this._items[this._offset + index];  
  95.             }  
  96.             set  
  97.             {  
  98.                 throw new NotImplementedException();  
  99.             }  
  100.         }  
  101.     }  

RowCollection.cs 行的绑定数据源的集合

 


  1. using System;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4. using System.Collections.Specialized;  
  5. using System.ComponentModel;  
  6. using System.Reflection;  
  7. using System.Threading;  
  8. using System.Windows;  
  9.  
  10. namespace GridListDemo  
  11. {  
  12.     public class RowCollection<T> : IList<GridDataRow<T>>, IList where T : new()  
  13.     {  
  14.         private IList<T> _itemsCollection;  
  15.         private int _rowItemCount;//一行的数量  
  16.  
  17.         public RowCollection(IList<T> itemsCollection, int rowItemCount)  
  18.         {  
  19.             this._itemsCollection = itemsCollection;  
  20.             this._rowItemCount = rowItemCount;  
  21.         }  
  22.  
  23.         public void Add(GridDataRow<T> item)  
  24.         {  
  25.             throw new NotImplementedException();  
  26.         }  
  27.  
  28.         public int Add(object value)  
  29.         {  
  30.             throw new NotImplementedException();  
  31.         }  
  32.  
  33.         public void Clear()  
  34.         {  
  35.             throw new NotImplementedException();  
  36.         }  
  37.  
  38.         public bool Contains(object value)  
  39.         {  
  40.             throw new NotImplementedException();  
  41.         }  
  42.  
  43.         public bool Contains(GridDataRow<T> item)  
  44.         {  
  45.             throw new NotImplementedException();  
  46.         }  
  47.  
  48.         public void CopyTo(Array array, int index)  
  49.         {  
  50.             throw new NotImplementedException();  
  51.         }  
  52.  
  53.         public void CopyTo(GridDataRow<T>[] array, int arrayIndex)  
  54.         {  
  55.             throw new NotImplementedException();  
  56.         }  
  57.  
  58.         public IEnumerator<GridDataRow<T>> GetEnumerator()  
  59.         {  
  60.             throw new NotImplementedException();  
  61.         }  
  62.  
  63.         public int IndexOf(object value)  
  64.         {  
  65.             return -1;  
  66.         }  
  67.  
  68.         public int IndexOf(GridDataRow<T> item)  
  69.         {  
  70.             return -1;  
  71.         }  
  72.  
  73.         public void Insert(int index, GridDataRow<T> item)  
  74.         {  
  75.             throw new NotImplementedException();  
  76.         }  
  77.  
  78.         public void Insert(int index, object value)  
  79.         {  
  80.             throw new NotImplementedException();  
  81.         }  
  82.  
  83.         public void Remove(object value)  
  84.         {  
  85.             throw new NotImplementedException();  
  86.         }  
  87.  
  88.         public bool Remove(GridDataRow<T> item)  
  89.         {  
  90.             throw new NotImplementedException();  
  91.         }  
  92.  
  93.         public void RemoveAt(int index)  
  94.         {  
  95.             throw new NotImplementedException();  
  96.         }  
  97.  
  98.         IEnumerator IEnumerable.GetEnumerator()  
  99.         {  
  100.             throw new NotImplementedException();  
  101.         }  
  102.  
  103.         public int Count  
  104.         {  
  105.             get  
  106.             {  
  107.                 //总数处于一行的数量等于列表的行数  
  108.                 return Convert.ToInt32(Math.Ceiling((double)(((double)this._itemsCollection.Count) / ((double)this._rowItemCount))));  
  109.             }  
  110.         }  
  111.  
  112.         public bool IsFixedSize  
  113.         {  
  114.             get  
  115.             {  
  116.                 return false;  
  117.             }  
  118.         }  
  119.  
  120.         public bool IsReadOnly  
  121.         {  
  122.             get  
  123.             {  
  124.                 throw new NotImplementedException();  
  125.             }  
  126.         }  
  127.  
  128.         public bool IsSynchronized  
  129.         {  
  130.             get  
  131.             {  
  132.                 return false;  
  133.             }  
  134.         }  
  135.  
  136.         public GridDataRow<T> this[int index]  
  137.         {  
  138.             get  
  139.             {  
  140.                 return new GridDataRow<T>(this._itemsCollection, index * this._rowItemCount, this._rowItemCount);  
  141.             }  
  142.             set  
  143.             {  
  144.                 throw new NotImplementedException();  
  145.             }  
  146.         }  
  147.  
  148.         public object SyncRoot  
  149.         {  
  150.             get  
  151.             {  
  152.                 return this;  
  153.             }  
  154.         }  
  155.  
  156.         object IList.this[int index]  
  157.         {  
  158.             get  
  159.             {  
  160.                 return this[index];  
  161.             }  
  162.             set  
  163.             {  
  164.                 throw new NotImplementedException();  
  165.             }  
  166.         }  
  167.     }  

MyGridRow.cs 自定义的组控件

 


  1. using System.Collections.Generic;  
  2. using System.Linq;  
  3. using System.Windows;  
  4. using System.Windows.Controls;  
  5. using System.Windows.Data;  
  6.  
  7. namespace GridListDemo  
  8. {  
  9.     /// <summary> 
  10.     /// 横向排版,继承Canvas控件  
  11.     /// </summary> 
  12.     public class MyGridRow : Canvas  
  13.     {  
  14.         //定义ItemsSource属性  
  15.         public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IList<Item>), typeof(MyGridRow), new PropertyMetadata(new PropertyChangedCallback(MyGridRow.OnItemsSourceChanged)));  
  16.         /// <summary> 
  17.         /// 初始化GridRow控件  
  18.         /// </summary> 
  19.         private void ApplyRaw()  
  20.         {  
  21.             if ((this.ItemsSource == null) || (this.ItemsSource.Count != base.Children.Count))  
  22.             {  
  23.                 base.Children.Clear();  
  24.                 if (this.ItemsSource != null)  
  25.                 {  
  26.                     for (int i = 0; i < this.ItemsSource.Count<Item>(); i++)  
  27.                     {  
  28.                         Item item = this.ItemsSource[i];  
  29.                         TextBlock tb = new TextBlock  
  30.                         {  
  31.                             DataContext = item,  
  32.                             Width = 80.0,  
  33.                             Height = 80.0  
  34.                         };  
  35.                         Binding binding = new Binding("Name")  
  36.                         {  
  37.                             FallbackValue = null 
  38.                         };  
  39.                         BindingOperations.SetBinding(tb, TextBlock.TextProperty, binding);  
  40.                         //添加目标到Canvas控件里面  
  41.                         base.Children.Add(tb);  
  42.                         Canvas.SetLeft(tb, (double)(i * 0x72));  
  43.                     }  
  44.                 }  
  45.             }  
  46.             else  
  47.             {  
  48.                 for (int j = 0; j < this.ItemsSource.Count<Item>(); j++)  
  49.                 {  
  50.                     Item item2 = this.ItemsSource[j];  
  51.                     TextBlock tb2 = (TextBlock)base.Children[j];  
  52.                     tb2.Text = item2.Name;  
  53.                 }  
  54.             }  
  55.         }  
  56.         /// <summary> 
  57.         /// ItemsSource改变事件  
  58.         /// </summary> 
  59.         /// <param name="d"></param> 
  60.         /// <param name="e"></param> 
  61.         private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  
  62.         {  
  63.             (d as MyGridRow).ApplyRaw();  
  64.         }  
  65.         //ItemsSource属性  
  66.         public IList<Item> ItemsSource  
  67.         {  
  68.             get  
  69.             {  
  70.                 return (IList<Item>)base.GetValue(ItemsSourceProperty);  
  71.             }  
  72.             set  
  73.             {  
  74.                 base.SetValue(ItemsSourceProperty, value);  
  75.             }  
  76.         }  
  77.     }  

在页面中实现

 


  1.  <phone:PhoneApplicationPage.Resources> 
  2.         <DataTemplate x:Key="GridViewTemplate"> 
  3.             <myControl:MyGridRow ItemsSource="{Binding}" Height="114" Width="480" /> 
  4.         </DataTemplate> 
  5.     </phone:PhoneApplicationPage.Resources> 
  6. .......  
  7. <ListBox Name="GridItemsListBox" HorizontalAlignment="Left" 
  8.                  ItemTemplate="{StaticResource GridViewTemplate}" /> 

 


  1. List<Item> source = new List<Item>();  
  2.             for (int i = 0; i < 200; i++)  
  3.             {  
  4.                 source.Add(new Item { Name = "name" + i });  
  5.             }  
  6.             this.GridItemsListBox.ItemsSource = new RowCollection<Item>(source, 4); 

运行的效果

 

Windows Phone 7 如何实现高效率的横向排版ListBox

 


本文转自linzheng 51CTO博客,原文链接:http://blog.51cto.com/linzheng/1078356