我正在尝试尽可能高效地使用我的应用程序,并且我已经阅读了有关ListBox在Windows Phone 8中自动虚拟化其数据的信息。我已经实现了我在ListBox中使用的ItemContainerStyle
样式,并且我不确定这是否会影响绑定到ListBox的项目的虚拟化。我的项目是图像,当MainPage初始化时,它们从IsolatedStorage加载到ObservableCollection中。这个解决方案好吗?如果没有,还有更好的建议吗?
风格
<phone:PhoneApplicationPage.Resources>
<Style x:Key="MyStyle" TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property ="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="LayoutRoot" Background="{TemplateBinding Background}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="brd" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TransparentBrush}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="ContentContainer" Storyboard.TargetProperty="Opacity" Duration="0" To=".5" />
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected">
</VisualState>
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="brd" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="0" Value="2" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
</VisualState>
<VisualState x:Name="Unfocused">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="brd" CornerRadius="10" BorderBrush="{StaticResource PhoneAccentBrush}" Width="Auto" BorderThickness="{TemplateBinding BorderThickness}">
<Viewbox MaxHeight="128" MaxWidth="128" >
<Image x:Name="recentImage" Source="{Binding Source}" Margin="12" Width="115"/>
</Viewbox>
</Border>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu x:Name="imgListContextMenu" Background="{StaticResource PhoneChromeBrush}">
<toolkit:MenuItem Foreground="{StaticResource PhoneForegroundBrush}" Header="edit" Click="editContextMenuItem_Click"/>
<toolkit:MenuItem Foreground="{StaticResource PhoneForegroundBrush}" Header="favorite" Click="favoriteContextMenuItem_Click"/>
<toolkit:MenuItem Foreground="{StaticResource PhoneForegroundBrush}" Header="delete" Click="deleteContextMenuItem_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:PhoneApplicationPage.Resources>
ListBox
<ListBox x:Name="Recent" Margin="8"
SelectionChanged="recent_SelectionChanged" toolkit:TiltEffect.IsTiltEnabled="True"
ItemContainerStyle="{StaticResource MyStyle}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
MainPage.xaml.cs中
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Recent.ItemsSource = App.PictureList.Pictures;
}
App.xaml.cs
public static PictureRepository PictureList
{
get
{
return PictureRepository.Instance;
}
}
PictureRepository.cs
#region Constants
public const string IsolatedStoragePath = "Pictures";
#endregion
#region Fields
private readonly ObservableCollection<Picture> _pictures = new ObservableCollection<Picture>();
#endregion
#region Properties
public ObservableCollection<Picture> Pictures
{
//get { return _pictures; }
get;
private set;
}
#endregion
#region Singleton Pattern
private PictureRepository()
{
LoadAllPicturesFromIsolatedStorage();
}
public static readonly PictureRepository Instance = new PictureRepository();
#endregion
/// <summary>
/// Saves to local storage
/// This method gets two parameters: the captured picture instance and the name of the pictures folder in the isolated storage
/// </summary>
/// <param name="capturedPicture"></param>
/// <param name="directory"></param>
public void SaveToLocalStorage(CapturedPicture capturedPicture, string directory)
{
//call IsolatedStorageFile.GetUserStoreForApplication to get an isolated storage file
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
//Call the IsolatedStorageFile.EnsureDirectory extension method located in the Common IsolatedStorageFileExtensions class to confirm that the pictures folder exists.
isoFile.EnsureDirectory(directory);
//Combine the pictures folder and captured picture file name and use this path to create a new file
string filePath = Path.Combine(directory, capturedPicture.FileName);
using (var fileStream = isoFile.CreateFile(filePath))
{
using (var writer = new BinaryWriter(fileStream))
{
capturedPicture.Serialize(writer);
}
}
}
/// <summary>
/// To load all saved pictures and add them to the pictures list page
/// </summary>
public CapturedPicture LoadFromLocalStorage(string fileName, string directory)
{
//To open the file, add a call to the IsolatedStorageFile.GetUserStoreForApplication
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
//Combine the directory and file name
string filePath = Path.Combine(directory, fileName);
//use the path to open the picture file from the isolated storage by using the IsolatedStorageFile.OpenFile method
using (var fileStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
{
//create a BinaryReader instance for deserializing the CapturedPicture instance
using (var reader = new BinaryReader(fileStream))
{
var capturedPicture = new CapturedPicture();
//create a new instance of the type CapturedPicture called CapturedPicture.Deserialize to deserialize the captured picture and return it
capturedPicture.Deserialize(reader);
return capturedPicture;
}
}
}
/// <summary>
/// To load all the pictures at start time
/// </summary>
private void LoadAllPicturesFromIsolatedStorage()
{
//add call to the IsolatedStorageFile.GetUserStoreForApplication to open an isolated storage file
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
//Call the IsolatedStorageFile.EnsureDirectory extension method located in the Common IsolatedStorageFileExtensions class to confirm that the pictures folder exists
isoFile.EnsureDirectory(IsolatedStoragePath);
//Call the IsolatedStorageFile.GetFileNames using the pictures directory and *.jpg as a filter to get all saved pictures
var pictureFiles = isoFile.GetFileNames(Path.Combine(IsolatedStoragePath, "*.jpg"));
var pictures = new List<Picture>();
//Iterate through all the picture files in the list and load each using the LoadFromLocalStorage you created earlier
foreach (var pictureFile in pictureFiles)
{
var picture = LoadFromLocalStorage(pictureFile, IsolatedStoragePath);
//_pictures.Add(picture);
pictures.Add(picture);
}
Pictures = new ObservableCollection<Picture>(pictures.OrderBy(x => x.DateTaken));
}
编辑**使用LongListSelector的新实现?
我在我的视图中将ListBox更改为LongListSelector
并设置似乎模仿WrapPanel的LayoutMode="Grid"
。我希望我需要的虚拟化能够存在。有什么建议或意见吗?
MainPage.xaml中
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="ItemTemplate">
<StackPanel Height="108" Width="108" Margin="6,6" Orientation="Horizontal">
<Viewbox Width="108" Height="108">
<Image x:Name="recentImage" Source="{Binding Source}" Margin="6,6" Width="108"/>
</Viewbox>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<phone:LongListSelector x:Name="Recent" Margin="8"
SelectionChanged="recent_SelectionChanged"
toolkit:TiltEffect.IsTiltEnabled="True"
LayoutMode="Grid" GridCellSize="108,108"
ItemTemplate="{StaticResource ItemTemplate}"/>
请注意
答案 0 :(得分:2)
你没有虚拟化。设置ListBox的ItemsPanel时,将删除虚拟化功能。
<ListBox x:Name="Recent" Margin="8"
SelectionChanged="recent_SelectionChanged" toolkit:TiltEffect.IsTiltEnabled="True"
ItemContainerStyle="{StaticResource MyStyle}">
<ListBox.ItemsPanel> <!-- This is removing virtualization-->
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
您可以通过删除ItemsPanel自定义并添加1000个项来对此进行测试。滚动列表框并查看控件的加载时间。重新添加自定义,您会注意到性能下降和加载时间增加。
那就是说,您可能希望了解一些WPF virtualizing wrap panels如何在WP8上运行。我在之前做过的WPF项目中尝试过这些项目,并没有像我希望的那样运气,但结果可能会有所不同。