无法使用yield绑定到IEnumerable实现

时间:2010-08-18 19:23:46

标签: wpf data-binding ienumerable yield

我有一个封装了一堆集合的类。我想将此类绑定到列表框以显示集合中的项目。该类实现了IEnumerable。显示列表框时,我希望调用IEnumerable.GetEnumerator方法。但是,当GetEnumerator方法使用yield关键字时,它不会。但是,如果我从List集合返回枚举器它可以正常工作,每次显示一个窗口时都会调用GetEnumerator方法。

List集合的枚举器有什么神奇之处??? 实现允许WPF项目控件获取快照(不需要更新)的正确接口是什么? IList是否可以使用???

下面的示例代码每次打开一个新窗口时都会添加一个时间戳。但是,列表框永远不会显示多个时间戳,即第一个(也是唯一一个)GetEnumerator被调用的时间戳数。计数增加,因此添加了时间戳。更改GetEnumerator方法以返回列表集合的枚举器将导致每次打开新窗口时都会调用GetEnumerator方法。

XAML:

<Window x:Class="YieldTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <StackPanel>
        <Button Content="Open" Click="Button_Click" />
        <TextBlock Text="{Binding Path=Count}" />
        <ListBox ItemsSource="{Binding}" />
    </StackPanel>
</Window>

代码背后:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;

namespace YieldTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Window1 window1 = new Window1();
            window1.DataContext = _timeStamps;
            _timeStamps.Add(DateTime.Now);
            window1.Show();
        }

        private static TimeStamps _timeStamps = new TimeStamps();
    }

    public class TimeStamps : IEnumerable
    {
        public void Add(DateTime time1)
        {
            _timeStamps.Add(time1);
        }

        public int Count { get { return _timeStamps.Count; } }

        public IEnumerator GetEnumerator()
        {
            Debug.WriteLine("GetEnumerator");
            // Returning the enumerator of _timeStamps will result in
            // GetEnumerator called every time a new window is opened,
            // which is the expected result
            // return _timeStamps.GetEnumerator();

            // Using yield will result in GetEnumerator is called only
            // one time for the first window opened. This means that
            // newer windows will have stale data.
            foreach (DateTime timeStamp in _timeStamps)
            {
                yield return timeStamp;
            }
        }

        private List<DateTime> _timeStamps = new List<DateTime>();
    }
}

1 个答案:

答案 0 :(得分:2)

当您设置ItemsSource时,WPF通过CollectionView访问它以启用排序,对e.t.c进行分组。视图是共享的,因此在您的情况下,每个ItemsControl都使用相同的枚举器,但它永远不会重置,因此只显示最后一个项目。

如果您想要快照行为,有几种方法,但为每个ItemsControl创建一个新列表是最简单的。

如果您希望所有这些内容同步并自动更新,请参阅ObservableCollection,其中INotifyCollectionChanged

你也应该使用通用的IEnumerable接口。