如果集合值相同,为什么LongListSelector会添加额外的项目?

时间:2014-03-25 12:19:48

标签: c# xaml windows-phone-8

昨天我在为WP编写演示应用程序时发现了这种奇怪的行为。通常我从不传递普通物品,也从不传递“相同” - 但这次我做了。 当绑定到int或string类型的observablecollection时,如果值相同,则控件将添加第一个项,然后是两个,然后是三个,然后是四个。而不是每次添加一个。基本上它是这样做的:

Items.Count ++

但是,如果我将项目(例如字符串)更改为唯一的(例如GUID.ToString),则它具有预期的行为。

这与DataContext的设置方式无关,或者我是否添加了LayoutMode =" List" IsGroupingEnabled ="假"控制。

为什么这样做?这是预期的行为吗?

我花了几个小时寻找答案,所以请不要粘贴关于控件的随机链接:)

视图代码:

<phone:PhoneApplicationPage
x:Class="Bug.MainPage"
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"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True"
DataContext="{Binding RelativeSource={RelativeSource Self}}">

<StackPanel>
    <Button Click="Button_Click">Add</Button>
    <phone:LongListSelector  Width="300" Height="600" ItemsSource="{Binding Items}"/>
</StackPanel>
</phone:PhoneApplicationPage>

代码背后:

using System.Collections.ObjectModel;
using System.Windows;


namespace Bug
{
    public partial class MainPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            Items = new ObservableCollection<string>();

            //DataContext = this;
        }

        public ObservableCollection<string> Items { get; set; }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Items.Add("A");

            // This works as expected
            //Items.Add(Guid.NewGuid().ToString());
        }
    }

}

4 个答案:

答案 0 :(得分:2)

这是LongListSelector中的一个错误。它与Guid一起使用的原因是因为它会进行参考比较并避免错误。

以下是使用引用对象的解决方法:

public partial class MainPage : PhoneApplicationPage
{
    // Constructor
    public MainPage()
    {
        InitializeComponent();

        // Sample code to localize the ApplicationBar
        Items = new ObservableCollection<Object>();

    }
    public ObservableCollection<Object> Items { get; set; }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Items.Add(new Object() { Value = "A" });

        // This works as expected
        //Items.Add(Guid.NewGuid().ToString());
    }

}
public class Object
{
    public string Value { get; set; }

    public override string ToString()
    {
        return Value;
    }
}

答案 1 :(得分:0)

这绝不是一个答案,但我修改了@ IrisClasson的原始代码,以更多地突出问题。如果您在添加项目之间交替使用&#34; A&#34;和一个项目&#34; B&#34;列表将在连续两次添加任一项时显示奇怪的行为,但在添加其他项时将自行更正。我添加了一个绑定到相同数据的ListBox,以便您可以看到列表的外观。

查看:

<phone:PhoneApplicationPage
    x:Class="Bug.MainPage"
    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"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <Button Click="Button_Click">Add A</Button>
            <Button Click="Button_Click1">Add B</Button>
            <Button Click="Button_Click2">Clear</Button>
        </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <phone:LongListSelector x:Name="MyLongList"  Width="200" Height="600" 
                                 ItemsSource="{Binding Items}"/>
        <ListBox x:Name="MyListBox" Width="200" Height="600" 
                 ItemsSource="{Binding Items}" />
    </StackPanel>
    </StackPanel>
</phone:PhoneApplicationPage>

代码隐藏:

using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using Microsoft.Phone.Controls;

namespace Bug
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            Items = new ObservableCollection<string>();

            Items.CollectionChanged += Items_CollectionChanged;
        }

        void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Debug.WriteLine("CollectionChanged");
        }

        public ObservableCollection<string> Items { get; private set; }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Items.Add("A");

            // This works as expected
            //Items.Add(Guid.NewGuid().ToString());
        }

        private void Button_Click1(object sender, RoutedEventArgs e)
        {
            Items.Add("B");

            // This works as expected
            //Items.Add(Guid.NewGuid().ToString());
        }

        private void Button_Click2(object sender, RoutedEventArgs e)
        {
            Items.Clear();
        }
    }
}

答案 2 :(得分:0)

我认为它在某种程度上与Two different "strings" are the same object instance?相关,所谓的字符串实习http://en.wikipedia.org/wiki/String_interning,这意味着它与多少&#34; A&#34;无关。你将创建它的字符串仍将指向相同的内存。

例如:如果你试图保存&#34; Guid.NewGuid()。ToString())&#34;进入私人领域并将该实例用于&#34; Items.Add(obj)&#34;它会导致同样的问题。

项目的计数也是正确的,因此它必须是LLS上的错误以及它呈现同一实例对象的方式。

答案 3 :(得分:-1)

我很确定它是LongListSelector的错误。

我认为,当它在数据之间加载差异时,它会将集合中的所有“A”外观列入列表。

让我们等待WP8.1,可能不推荐使用LongListSelector: - )

VJ