使用带有多个ListView的<scrollviewer>时出现内存不足</scrollviewer>

时间:2014-09-30 13:41:29

标签: c# xaml out-of-memory windows-phone-8.1

我有一个带有2个ListViews的usercontrol。一个用于保存预定义类别列表,一个用于包含其中所有类别的列表。 当我将ListView放在<Grid>内时,一切都很完美。 工作的xaml代码(使用Grid):

<Grid Style="{StaticResource ResourceKey=ContentStyle}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ListView x:Name="lstPredefinedCategories" Grid.Row="0" ItemsSource="{Binding PredefinedCategories}" SelectionMode="Multiple" Margin="20">
            <ListView.Header>
                <StackPanel>
                    <TextBlock Text="Voorgestelde categorie&#235;n" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
                    <Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
                </StackPanel>
            </ListView.Header>

            <ListView.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" Margin="20,0">
                <TextBlock Text="Alle categorie&#235;n" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
                <Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
            </StackPanel>
            <TextBox x:Name="txtSearch" PlaceholderText="Zoek categorie" Grid.Row="1" Style="{StaticResource SearchboxStyle}" Margin="20,0" TextChanged="txtSearch_TextChanged" />
            <Rectangle Grid.Row="2" Style="{StaticResource DividerStyle}" Margin="20, 0" />
            <ListView x:Name="lstCategories" Grid.Row="3" Margin="20,10,20,0" ItemsSource="{Binding Categories}" SelectionMode="Multiple" SelectionChanged="lstCategories_SelectionChanged">

                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Key}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <Rectangle Grid.Row="4" Style="{StaticResource DividerStyle}" Margin="20, 0" />
            <Grid Grid.Row="5">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Button x:Name="btnAnnuleren" Grid.Column="0" Content="Annuleren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnAnnuleren_Click"/>
                <Rectangle Grid.Column="1" Fill="#A9A9A9" Width="0.5" Margin="10,0" />
                <Button x:Name="btnSelecteren" Grid.Column="2" Content="Selecteren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnSelecteren_Click"/>
            </Grid>
        </Grid>
    </Grid>

唯一的问题是我没有得到我想要的UI行为。如果我使用网格,那么只有红色边框可滚动(因为ListView)。但我需要的是整个绿色边框是可滚动的。

WP layout

所以我想将所有内容都放在<ScrollViewer><StackPanel></StackPanel></ScrollViewer>中。 但是当我这样做时,我偶尔会遇到一个内存不足的异常(有时应用程序会冻结并关闭而没有例外)。

以下是我使用<ScrollViewer>

的xaml
<ScrollViewer>
        <StackPanel>
            <ListView x:Name="lstPredefinedCategories" ItemsSource="{Binding PredefinedCategories}" SelectionMode="Multiple" Margin="20">
                <ListView.Header>
                    <StackPanel>
                        <TextBlock Text="Voorgestelde categorie&#235;n" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
                        <Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
                    </StackPanel>
                </ListView.Header>

                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0" Margin="20,0">
                    <TextBlock Text="Alle categorie&#235;n" Style="{StaticResource TextBlockStyle}" FontWeight="SemiBold" Foreground="Black" />
                    <Rectangle Style="{StaticResource DividerStyle}" Fill="Black"/>
                </StackPanel>
                <TextBox x:Name="txtSearch" PlaceholderText="Zoek categorie" Grid.Row="1" Style="{StaticResource SearchboxStyle}" Margin="20,0" TextChanged="txtSearch_TextChanged" />
                <Rectangle Grid.Row="2" Style="{StaticResource DividerStyle}" Margin="20, 0" />
                <ListView x:Name="lstCategories" Grid.Row="3" Margin="20,10,20,0" ItemsSource="{Binding Categories}" SelectionMode="Multiple" SelectionChanged="lstCategories_SelectionChanged">

                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Key}" Style="{StaticResource TextBlockStyle}" HorizontalAlignment="Left" TextWrapping="Wrap" Width="300" />
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
                <Rectangle Grid.Row="4" Style="{StaticResource DividerStyle}" Margin="20, 0" />
                <Grid Grid.Row="5">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Button x:Name="btnAnnuleren" Grid.Column="0" Content="Annuleren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnAnnuleren_Click"/>
                    <Rectangle Grid.Column="1" Fill="#A9A9A9" Width="0.5" Margin="10,0" />
                    <Button x:Name="btnSelecteren" Grid.Column="2" Content="Selecteren" Style="{StaticResource ButtonAnnulerenStyle}" Click="btnSelecteren_Click"/>
                </Grid>
            </Grid>
        </StackPanel>
    </ScrollViewer>

有关为什么我的应用程序冻结或获得OOM异常的任何想法?

更新

这是因为在第二个ListView中它们加载的对象太多了。因此,我将尝试使用ISupportIncrementalLoading进行修复。

或者还有其他方式吗?

1 个答案:

答案 0 :(得分:2)

解决方案是使用虚拟化(ISupportIncrementalLoading),如评论中建议的那样。

在这里,您可以找到我的ISupportIncrementalLoading实现类:

public class StringKeyValueIncrementalCollection : ObservableCollection<StringKeyValue>, ISupportIncrementalLoading
    {

        private List<StringKeyValue> allCategories;
        private int lastItem = 1;

        public StringKeyValueIncrementalCollection(List<StringKeyValue> categories)
        {
            this.allCategories = categories;
        }

        public bool HasMoreItems
        {
            get
            {
                if (lastItem == allCategories.Count)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {

            CoreDispatcher coreDispatcher = Window.Current.Dispatcher;

            return Task.Run<LoadMoreItemsResult>(async () =>
            {

                List<StringKeyValue> items = new List<StringKeyValue>();
                for (int i = 0; i < count; i++)
                {
                    items.Add(allCategories[i]);
                    lastItem++;
                    Debug.WriteLine(lastItem);
                    if (lastItem == allCategories.Count)
                    {
                        break;
                    }
                }

                await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () =>
                    {
                        foreach (StringKeyValue item in items)
                        {
                            this.Add(item);
                        }
                    });

                return new LoadMoreItemsResult() { Count = count };
            }).AsAsyncOperation<LoadMoreItemsResult>();
        }
    }

然后我的代码在ViewModel中。如您所见,我使用StringKeyValueIncrementalCollection而不是常规List<object>

    private StringKeyValueIncrementalCollection categories;
    private StringKeyValueIncrementalCollection allCategories;

    public StringKeyValueIncrementalCollection Categories
    {
        get { return categories; }
        set
        {
            filteredCategories = value;
            RaisePropertyChanged("Categories");
        }
    }
    public async void LoadCategories()
    {
        List<StringKeyValue> temp = await this.openVlaanderenService.GetCategoriesData();
        allCategories = new StringKeyValueIncrementalCollection(temp);
        Categories = allCategories;
    }

你遇到的唯一问题是ScollViewer会允许它的内容填充所需的空间,因此数据会继续加载。为了解决这个问题,我完成了ISupportIncrementalLoading inside ScrollViewer not supported?

中的建议

所以我在ScrollViewer中添加了一个SizeChanged="ScrollViewer_SizeChanged"事件,在后面的代码中根据ScrollViewer的视口大小属性设置了ListView的大小:

private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
{
    lstCategories.Height = scrollViewer.ViewportHeight;
}