I'm working on WP8.1 and I've found strage behaviour of my Listbox - to make it easier to reproduce I've put the code here. The problem occurs both on device and emulator.
I've a Listbox which is bound to ObservableCollection and it is filled with items upon button click:
public sealed partial class MainPage : Page
{
List<string> populationOfItems = new List<string>();
ObservableCollection<string> itemsToView = new ObservableCollection<string>();
public MainPage()
{
this.InitializeComponent();
second.Click += second_Click;
myList.ItemsSource = itemsToView;
// populate list of items to be copied
for (int i = 0; i < 6; i++) populationOfItems.Add("Item " + i.ToString());
BottomAppBar = new CommandBar();
}
private async void second_Click(object sender, RoutedEventArgs e)
{
itemsToView.Clear();
await PopulateList();
}
private async Task PopulateList()
{
await Task.Delay(100); // without this line code seems to work ok
itemsToView.Add("FIRSTELEMENT"); // add first differet element
foreach (var item in populationOfItems)
itemsToView.Add(item);
}
}
The first time I fill the list, everthing is ok (pic. 1). But when I hit the button second time and, I can see elements not from first but from second (pic. 2). Ok - it is above, but I'm anable to scroll to it, when I hold my finger (mouse) I can scroll list and see that it exists, but when I stop scrolling the list hides (scrolls to second element) the first element. Also when you select any item - the list seems to look ok while you hold your finger (pic. 3), when you release it hides the first element again. When you move the list few time up/down, it repairs and works normal.
The way to reproduce the issue:
- click the scond button once - fill the list
- scroll list down, so that you hide the first elements (this is important)
- hit the second button once more
- try to scroll the list up and see first element, release finger
Pic.1
Pic.2
Pic.3
The problem seems to be concerned with asynchronous Task (that is why I also tagged this question asynchronous) - without the line await Task.Delay(100);
, the code seems to work ok.
Does anybody have an idea what can be wrong?
EDIT - some other attempts
I've also tried running populating process via Dispatcher
, without success - the problem exists.
I've also made an attempt to populate a temporary List
(not ObservableCollection) and after returning from async Task
, populate ObservableCollection - the problem persists.
List<string> temporaryList = new List<string>();
private async Task PopulateList()
{
await Task.Delay(100); // without this line code seems to work ok
temporaryList.Clear();
temporaryList.Add("FIRSTELEMENT"); // add first differet element
foreach (var item in populationOfItems)
temporaryList.Add(item);
}
private async void second_Click(object sender, RoutedEventArgs e)
{
itemsToView.Clear();
await PopulateList();
foreach (var item in temporaryList)
itemsToView.Add(item);
}
Edit 2 - returnig List created in acync Task also doesn't help much:
private async void second_Click(object sender, RoutedEventArgs e)
{
itemsToView.Clear();
var items = await PopulateList();
foreach (var item in items)
itemsToView.Add(item);
}
private async Task<IEnumerable<string>> PopulateList()
{
await Task.Delay(100); // without this line code seems to work ok
List<string> temporaryList = new List<string>();
temporaryList.Add("FIRSTELEMENT"); // add first differet element
foreach (var item in populationOfItems)
temporaryList.Add(item);
return temporaryList;
}
EDIT 3 - as I've checked the same code run under Windows Phone 8.1 Silverlight works without problems.
You should not mix UI handling with data retrieval because they are now happening concurrently.
Be also aware that when you call
await PopulateList()
the execution flow goes back to the UI thread and is ready to accept clicks and fire click events.Try this instead:
You might want to read this:
EDIT:
I believe this demonstrates what you're trying to do. I've added a few more delays for you to see it happening on the phone.
MainPage.xaml
MainPage.xaml.cs