std.denis
std.denis

Reputation: 317

Why moving an item in LongListSelector results to missing items

I'm using plain list in LongListSelector with ObservableCollection as ItemSource.

Initially all fine - scrolling to the end of list and back to the beginning has no troubles.

But then I call ObservableCollection.Move(2, 1). And now, when I scroll to the end and back to the top (so items are re-realized) I'm getting a partial list - random number of items from beginning of the list are absent (for example: 1,2,3...100 is changing to 1,3,42,43..100).

Am I doing something in a wrong way, or it is a bug in LongListSelector?

Here is a minimal example for my issue:

TestPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Collections.ObjectModel;

namespace myApp.Pages
{
    public class Item
    {
        public string Text { get; set; }
    }

    public class ItemsViewModel
    {
        public ObservableCollection<Item> UngroupedItems { get; set; }
    }

    public partial class TestPage : PhoneApplicationPage
    {
        ItemsViewModel _vm;
        public TestPage()
        {
            InitializeComponent();

            _vm  = new ItemsViewModel();
            _vm.UngroupedItems = new ObservableCollection<Item>();

            for (int i = 0; i < 100; i++)
            {
                _vm.UngroupedItems.Add(new Item() { Text = string.Format("- line {0}", _vm.UngroupedItems.Count + 1) });
            }

            DataContext = _vm;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _vm.UngroupedItems.Move(2, 1);
        }
    }
}

TestPage.xaml

<phone:PhoneApplicationPage
    x:Class="myApp.Pages.TestPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <phone:LongListSelector ItemsSource="{Binding UngroupedItems}">
            <phone:LongListSelector.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Text}" Style="{StaticResource PhoneTextTitle2Style}"/>
                </DataTemplate>
            </phone:LongListSelector.ItemTemplate>
        </phone:LongListSelector>
        <Button VerticalAlignment="Bottom"  Content="Test" Click="Button_Click"></Button>
    </Grid>
</phone:PhoneApplicationPage>

Upvotes: 1

Views: 124

Answers (1)

Chubosaurus Software
Chubosaurus Software

Reputation: 8161

I never like that function when Binding.

You can see it doesn't even update your long list selector until you scroll back to the portion that has changed, which is not ideal.

At this point, I think you have to safely do the move yourself unless someone else has a better idea.

private void Button_Click(object sender, RoutedEventArgs e)
{
    SafeMove(2, 1);
}

private void SafeMove(int old_index, int new_index)
{
     var saved_item = _vm.UngroupedItems[old_index];           
    _vm.UngroupedItems.RemoveAt(old_index);
    _vm.UngroupedItems.Insert(new_index, saved_item);
}

Template Version

private void SafeMove<T>(ref ObservableCollection<T> collection, int old_index, int new_index)
{

    var saved_item = collection[old_index];
    collection.RemoveAt(old_index);
    collection.Insert(new_index, saved_item);  

}


Using the safe move, you will see that the long list selector is updated immediately.

Upvotes: 1

Related Questions