我有一个封装了一堆集合的类。我想将此类绑定到列表框以显示集合中的项目。该类实现了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>();
}
}
答案 0 :(得分:2)
当您设置ItemsSource时,WPF通过CollectionView访问它以启用排序,对e.t.c进行分组。视图是共享的,因此在您的情况下,每个ItemsControl都使用相同的枚举器,但它永远不会重置,因此只显示最后一个项目。
如果您想要快照行为,有几种方法,但为每个ItemsControl创建一个新列表是最简单的。
如果您希望所有这些内容同步并自动更新,请参阅ObservableCollection,其中INotifyCollectionChanged。
你也应该使用通用的IEnumerable接口。