<ListBox x:Name="lb">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}"/>
<Image Source="{Binding ImageSource}" Height="200"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
public class Data : INotifyPropertyChanged
{
//图片名
public string Name { get; set; }
//当前页面对象用于角发UI线程
public Page Page { get; set; }
private Uri imageUri;
public Uri ImageUri
{
get { return imageUri; }
set
{
if (value != imageUri)
{
imageUri = value;
}
}
}
WeakReference bitmapImage;
public ImageSource ImageSource
{
get
{
if (bitmapImage != null)
{
if (bitmapImage.IsAlive)
{
return (ImageSource)bitmapImage.Target;
}
else
{
Debug.WriteLine("图片占用的被回收了");
}
}
if (imageUri != null)
{
Task.Factory.StartNew(() =>
{
DownloadImage(imageUri);
});
}
return null;
}
}
void DownloadImage(object state)
{
HttpWebRequest request = WebRequest.CreateHttp(state as Uri);
request.BeginGetResponse(DownLoadImageComplete, request);
}
void DownLoadImageComplete(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
Stream stream = response.GetResponseStream();
int length = int.Parse(response.Headers["Content-Length"]);
Stream streamForUri = new MemoryStream(length);
byte[] buffer = new Byte[length];
int read = 0;
do
{
read = stream.Read(buffer, 0, length);
streamForUri.Write(buffer, 0, read);
}
while(read==length);
streamForUri.Seek(0, SeekOrigin.Begin);
Page.Dispatcher.BeginInvoke(() =>
{
BitmapImage bm = new BitmapImage();
bm.SetSource(streamForUri);
if (bitmapImage == null)
{
bitmapImage = new WeakReference(bm);
}
else
{
bitmapImage.Target = bm;
}
OnPropertyChanged("ImageSource");
});
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string proName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(proName));
}
}
}
List<Data> list = new List<Data>();
for (int i = 0; i < 1000; i++)
{
list.Add(new Data
{
Page = this,
Name = i.ToString(),
ImageUri = new Uri("http://static.cnbetacdn.com/newsimg/110510/0657270304679663.jpg", UriKind.RelativeOrAbsolute),
});
}
lb.ItemsSource = list;
这贴子内容来自<深入理解windows phone 8.1 UI控件编程>的301页
使用书上的代码对ListBox进行测试,发现改变ListBox的ScrollViewer和ItemPresenter的结构,会使用虚拟化功能失效.
默认情况下应该是这样的:
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer>
<ItemsPresenter/>
</ScrollViewer></span>
</ControlTemplate>
</ListBox.Template>
改变ScrollViewer和ItemPresenter的结构,就是类似这样(只要是ScrollViewer和ItemPresenter之间加入了其它控件就破坏了虚拟化功能)
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer>
<StackPanel Orientation="Vertical">
<ItemsPresenter/>
<Button Content="这样就完全破坏了虚拟化功能"/>
</StackPanel>
</ScrollViewer></span>
</ControlTemplate>
</ListBox.Template>
在大多数情况下,最浪费时间的就是UI的创建.虚拟化功能可以保证只创建屏幕区域内的UI元素,如果数据源中包含的元素数据量过多时,虚拟化功能可以节约程序的内存.如果像上面一样坏虚拟化功能,在使用大数据源初始化ListBox后,会一次性创建所有列表基, 手机的内存可能会吃不销.
上面那个例子是异步加载图片,然后用ListBox显示,这个例子有两个性能问题.
1 Data对象中图片占用的内存
把ImageSource属性设置成WeakRefrence是为了,让图片对象尽可能快的被GC回收来释放内存.
3.异步加载.