3

我已经制作了一个很好的小三项宽列表作为开关工作的瓷砖。它看起来像这样:

瓷砖切换器

看起来不错吧?好吧,我在垂直滚动列表中有大约 130 个这样的图块,加载需要很长时间。根据性能分析工具,每个元素渲染大约需要 18 毫秒——这给了我大约 2.3 秒的渲染时间。在设备上,它通常是那个时间的两倍。这并不是真正的危机,但在绘制这些元素之前,UI 是完全黑色的并且没有响应。

在网上进行了一些研究后,我意识到这是因为WrapPanel工具包中的控件没有虚拟化它的项目 - 因此GPU一次渲染所有对象(在此过程中占用了大量内存)。

现在,有什么方法可以让这一切变得更快吗?

XAML:

<ListBox x:Name="ChannelsListBox" Grid.Row="2" Margin="0,40,0,0">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <toolkit:WrapPanel />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.Template>
        <ControlTemplate>
            <ItemsPresenter />
        </ControlTemplate>
    </ListBox.Template>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid x:Name="ChannelTile" Margin="6,6,6,6" Tap="ChannelTile_Tap">
                <!-- context menu code removed -->
                <Rectangle Width="136" Height="136" Fill="{StaticResource LightGrayColor}" />    
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

ListBoxItemsSource 设置在代码隐藏中 - 如果您想知道的话。

4

2 回答 2

3

好吧,如果您从另一个线程异步填充列表框,您可以避免无响应的 UI。

编辑2:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        /* In the xaml code:
           <ListBox x:Name="ChannelsListBox" ItemsSource="{Binding ListOfTestClasses}" ...
        */

        var vm = new MainPageViewModel();
        DataContext = vm;

        vm.StartLoadingDataAsync(10000);
    }
}

public class MainPageViewModel
{
    public ObservableCollection<TestClass> ListOfTestClasses { get; set; }
    private BackgroundWorker workerThread;
    public MainPageViewModel()
    {
        ListOfTestClasses = new ObservableCollection<TestClass>();
        workerThread = new BackgroundWorker();
        workerThread.DoWork += new DoWorkEventHandler((object sender, DoWorkEventArgs e) =>
        {
            for (int i = 0; i < (int)e.Argument; i++)
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    ListOfTestClasses.Add(new TestClass { Text = "Element " + (i + 1) });
                });

                Thread.Sleep(150);
            }
        });
    }

    public void StartLoadingDataAsync(int numberOfElements)
    {
        workerThread.RunWorkerAsync(numberOfElements);   
    }
}

public class TestClass
{
    public string Text { get; set; }
}
于 2012-07-10T12:50:54.940 回答
1

一些可能有用的想法:

  1. 查找或实现一个虚拟化 WrapPanel。这是最合适的解决方案,但我认为我还没有看到一个可靠的实现。但是为了这个目的,也许你不需要完美,并且可以摆脱别人已经写过的东西。
  2. 使用包含水平 StackPanel 子项的父虚拟化垂直 StackPanel。为此,您需要将单个数据序列重新塑造成较短的 3 项条目序列。但是,这可能并不难,并且应该为您提供理想解决方案的大部分好处。
  3. 考虑像我为 DeferredLoadListBox 所做的那样实现“惰性”容器。基本思想是延迟渲染容器,直到它们出现在屏幕上。我在这里有更多信息和示例代码:http: //blogs.msdn.com/b/delay/archive/2010/09/08/never-do-today-what-you-can-put-off-till-tomorrow -deferredloadlistbox-and-stackpanel-help-windows-phone-7-lists-scroll-smoothly-and-consistently.aspx
于 2012-07-10T16:14:37.337 回答