列表框-无法在填充ItemsSource之后选择第一个元素 [英] Listbox - inability to select the first element after populating ItemsSource

查看:77
本文介绍了列表框-无法在填充ItemsSource之后选择第一个元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究WP8.1,并且发现了Listbox的临时行为-为了简化复制,我将

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.

我有一个绑定到ObservableCollection的列表框,单击按钮后它就会充满项目:

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);
    }
}

我第一次填写列表,一切都很好(图1).但是当我第二次按下按钮时,我看到的元素不是第一次出现,而是第二次出现(图2).好的-它在上面,但是我可以滚动到它,当我按住手指(鼠标)时,我可以滚动列表并看到它存在,但是当我停止滚动列表时,第一个隐藏(滚动到第二个元素)元素.同样,当您选择任何项目时-按住手指时列表似乎看起来不错(图3),放开时该列表再次隐藏了第一个元素.向上/向下移动列表几次后,它可以修复并正常工作.

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.

重现问题的方法:

  • 单击scond按钮一次-填写列表
  • 向下滚动列表,以便隐藏前几个元素(这很重要)
  • 再次点击第二个按钮
  • 尝试向上滚动列表,查看第一个元素,松开手指
  • 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

图片1

图2

图3

问题似乎与异步Task有关(这就是为什么我也将此问题标记为异步)的原因-如果没有await Task.Delay(100);行,代码似乎可以正常工作.

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?

编辑-其他一些尝试

我也尝试通过Dispatcher运行填充过程,但没有成功-问题存在.

I've also tried running populating process via Dispatcher, without success - the problem exists.

我也尝试填充临时List(不是ObservableCollection),并且从async Task返回后,填充ObservableCollection-问题仍然存在.

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);
}

编辑2 -在acync Task中创建的returnig列表也无济于事:

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;
}

编辑3 -我已经检查了在Windows Phone 8.1下运行的相同代码,Silverlight可以正常工作.

EDIT 3 - as I've checked the same code run under Windows Phone 8.1 Silverlight works without problems.

推荐答案

您不应将UI处理与数据检索混合使用,因为它们现在同时发生.

You should not mix UI handling with data retrieval because they are now happening concurrently.

还请注意,当您调用await PopulateList()时,执行流程将返回到UI线程,并准备接受点击和触发点击事件.

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.

尝试以下方法:

private async void second_Click(object sender, RoutedEventArgs e)
{
    // UI thread
    var items = await PopulateListAsync(); // -> return to UI thread
    // back to UI thread
    itemsToView.Clear();
    itemsToView.Add("FIRSTELEMENT"); // add first differet element
    foreach (var item in items)
    {
        itemsToView.Add(item);
    }
}

private async Task<IEnumerable<string>> PopulateListAsync()
{
    // caller thread - UI thread
    await Task.Delay(100)
        .ConfigureAwait(continueOnCapturedContext: false);
    // some other thread
    return populationOfItems;
}

您可能需要阅读以下内容:

You might want to read this:

  • Asynchronous Programming with Async and Await (C# and Visual Basic)
  • Task-based Asynchronous Pattern (TAP)
  • Best Practices in Asynchronous Programming

我相信这可以证明您正在尝试做的事情.我为您添加了一些延迟,以便您在电话上看到它的发生.

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

<phone:PhoneApplicationPage
    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"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    x:Class="PhoneApp1.MainPage"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <phone:LongListSelector x:Name="List" HorizontalAlignment="Stretch" Margin="0" VerticalAlignment="Stretch" ItemsSource="{Binding}" LayoutMode="List">
                <phone:LongListSelector.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}" Style="{StaticResource PhoneTextExtraLargeStyle}" />
                    </DataTemplate>
                </phone:LongListSelector.ItemTemplate>
            </phone:LongListSelector>
            <Button Content="Button" Margin="0" Grid.Row="1" Click="Button_Click" x:Name="Button1"/>

        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

MainPage.xaml.cs

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Phone.Controls;

namespace PhoneApp1
{
    public partial class MainPage : PhoneApplicationPage
    {
        private List<string> populationOfItems = new List<string>
        {
            "one",
            "two",
            "three",
            "four",
            "five"
        };
        private ObservableCollection<string> itemsToView = new ObservableCollection<string>();

        public MainPage()
        {
            InitializeComponent();
            this.DataContext = this.itemsToView;
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Button1.IsEnabled = false;
            var items = await PopulateListAsync();
            itemsToView.Clear();
            await Task.Delay(100);
            itemsToView.Add("FIRSTELEMENT");
            foreach (var item in items)
            {
                await Task.Delay(10);
                itemsToView.Add(item);
            }
            this.Button1.IsEnabled = true;
        }
        private async Task<IEnumerable<string>> PopulateListAsync()
        {
            await Task.Delay(100)
                .ConfigureAwait(continueOnCapturedContext: false);
            return populationOfItems;
        }
    }
}

这篇关于列表框-无法在填充ItemsSource之后选择第一个元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆