长列表选择器和数据模板选择器

8
我正在使用LongListSelector来实现我的项目的列表或网格显示。为此,我创建了一个DataTemplateSelector,并在运行时更改了LayoutMode属性。这个方法能够工作,但是DataTemplateSelector似乎存在一些问题。如果我最初启动页面,DataTemplateSelector将被调用三次以处理我的三个项目。当我导航到另一个页面(设置页面以更改LayoutMode)然后返回时,DataTemplateSelector仅被调用两次,但仍然有三个项目。
DataTemplateSelector:
public abstract class DataTemplateSelector : ContentControl
{
    public virtual DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        return null;
    }

    protected override void OnContentChanged(object oldContent, object newContent)
    {
        base.OnContentChanged(oldContent, newContent);

        ContentTemplate = SelectTemplate(newContent, this);
    }
}

ItemViewModeTemplateSelector:

public class ItemViewModeTemplateSelector: DataTemplateSelector
{
    public DataTemplate ListViewModeTemplate
    {
        get;
        set;
    }

    public DataTemplate GridViewModeTemplate
    {
        get;
        set;
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        ViewMode viewMode = ViewMode.Grid;

        // Get ViewMode from IsolatedStorageSettings...

        switch (viewMode)
        {
            case ViewMode.Grid:
                return GridViewModeTemplate;

            case ViewMode.List:
                return ListViewModeTemplate;
        }

        return base.SelectTemplate(item, container);
    }
}

MainPage.xaml:

<phone:LongListSelector x:Name="ItemLongListSelector" ItemsSource="{Binding Items}" LayoutMode="Grid" GridCellSize="222,222">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <common:ItemViewModeTemplateSelector Content="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
                <common:ItemViewModeTemplateSelector.GridViewModeTemplate>
                    <DataTemplate>
                        <StackPanel Margin="12,12,0,0" Background="{Binding Color, Converter={StaticResource ColorToBrushConverter}}">
                            <!-- Content -->
                        </StackPanel>
                    </DataTemplate>
                </common:ItemViewModeTemplateSelector.GridViewModeTemplate>

                <common:ItemViewModeTemplateSelector.ListViewModeTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <!-- Content -->
                        </StackPanel>
                    </DataTemplate>
                </common:ItemViewModeTemplateSelector.ListViewModeTemplate>
            </common:ItemViewModeTemplateSelector>
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

这是我最初打开页面时的显示: 然后我导航到另一个页面,再返回: 编辑:我为这个问题准备了一个示例项目。它应该没有问题运行。
项目:http://sdrv.ms/1cAbVxE

我已经添加了一个示例项目! - zirkelc
你找到问题了吗? - Swift Sharp
不,问题仍然存在! - zirkelc
确实,那是一个非常好奇的问题。我知道这听起来有点无聊,但如果您使用ListBox并绑定ItemTemplate呢? - Swift Sharp
我已经在使用ListBox,但是我想切换到LongListSelector,因为它与ContextMenu的兼容性不太好。你可以在这里看到我在ListBox上遇到的问题:http://stackoverflow.com/questions/19609850/windows-phone-listbox-with-tiles-and-contextmenu-isenabled-binding-does-not-w - zirkelc
3个回答

4
我没有解决方案,但或许可以给将要解决这个问题的人一些线索。
我认为问题出在LongListSelector.UpdateLayout()方法上-当它被第一次触发时,没有项目与LLS绑定-OnChangeMethod会被调用多次,每次调用的数量等于Itemsource.Count。但是当我们离开页面并返回时-LLS已更新,该方法被调用,省略了中间元素。
这意味着它适用于偶数项- OnChangeMethod被正确调用的次数,但对于奇数项-它被调用次数-1。
第二个问题是为什么它会在没有更改的情况下被调用。

我还添加了一个代码来处理它(非常简单)。

3

我在我的应用程序中也做了类似的事情,但允许用户使用应用栏按钮选择LLS的LayoutMode。我基本上在代码中更改了LongListSelector.LayoutMode和它的ItemTemplate,然后LLS会自动刷新。我不确定这是否有帮助,但是这是我的代码。

private void layoutModeButton_Click(object sender, EventArgs e)
    {
        ApplicationBarIconButton layoutModeButton = (ApplicationBarIconButton)ApplicationBar.Buttons[0];

        if (MainLongListSelector.LayoutMode == LongListSelectorLayoutMode.Grid)
        {
            MainLongListSelector.LayoutMode = LongListSelectorLayoutMode.List;
            MainLongListSelector.ItemTemplate = this.Resources["ListListLayout"] as DataTemplate;
            layoutModeButton.IconUri = _gridButtonUri;
            layoutModeButton.Text = "grid";
        }
        else
        {
            MainLongListSelector.LayoutMode = LongListSelectorLayoutMode.Grid;
            MainLongListSelector.ItemTemplate = this.Resources["GridListLayout"] as DataTemplate;
            layoutModeButton.IconUri = _listButtonUri;
            layoutModeButton.Text = "list";
        }
    }

也许你已经找到了答案,但是为了增加讨论:对于相当大量的数据,这给我带来了非常好的性能。在更改设置后导航回页面时,也许你可以尝试类似的方法?


这也可以!我认为这似乎是更加性能友好的方式。谢谢。 - zirkelc

1

这里有一种解决方法。(也许问题会在WP 8.1更新时得到修正,连同我发现与LLS一起工作的其他。我知道 - 这个想法很丑陋、困难等等,但也许对您的目的来说已经足够了:

由于问题涉及“重新加载”LLS,我强制每次导航到页面时都初始化它(实际上我需要初始化整个页面 - 只有LLS不起作用)。我将InitializeComponent()和按钮事件等移动到OnNavigatedTo()中:

 protected override void OnNavigatedTo(NavigationEventArgs e)
  {
     base.OnNavigatedTo(e);

     this._contentLoaded = false;
     InitializeComponent();

     first.Click += first_Click;
     second.Click += second_Click;
     ItemLongListSelector.ItemsSource = Items;
  }

至少OnContentChanged()会被触发那么多次,代码可以在这里找到。

这个可以用,但我不确定它对于大量项目的性能会有什么影响。我会测试一下,如果太糟糕了,我就会删除更改布局模式的选项。谢谢,这帮了我很多! :) - zirkelc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接