2010-08-18 20 views
2

我有一個封裝了一堆集合的類。我想將此類綁定到列表框以顯示集合中的項目。該類實現IEnumerable。當列表框顯示時,我期待IEnumerable.GetEnumerator方法被調用。然而,GetEnumerator方法不使用yield關鍵字。但是,如果我要從列表集合中返回枚舉器,它將正常工作,每次顯示窗口時都會調用GetEnumerator方法。無法使用收益綁定到IEnumerable實現

列表集合的枚舉器如此神奇? 什麼是實現允許WPF itemscontrol獲取快照的正確界面(不需要更新)??? 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

我發現爲我獲得可綁定數據源的兩種解決方案是要麼實現IList和IEnumerator,要麼實現IEnumerable和INotifyCollectionChanged。我決定讓數據源實現IEnumerable和INotifyCollectionChanged,因爲它實現的不多,並且項目不能被客戶端代碼添加。 – 2010-08-23 14:12:49

回答

2

當您設置的ItemsSource WPF訪問它通過CollectionView啓用排序,分組e.t.c.該視圖是共享的,因此在您的情況下,每個ItemsControl使用的是相同的枚舉器,但不會重置,因此只顯示最後一個項目。

如果你想快照行爲有幾個方法,但爲每個ItemsControl創建一個新列表是最簡單的。

如果你想讓它們全部同步並自動更新,請參閱ObservableCollection,它實現了INotifyCollectionChanged

您應該也可以使用通用的IEnumerable接口。

+0

我也看到WPF使用collectionviews來獲取數據。爲什麼列表中的枚舉器不能重置枚舉器?在使用收益率時,它會創建什麼樣的collectionview? – 2010-08-18 20:54:51

+0

找到了這個答案,它猜測產量和重置。感謝您指導我正確的方向。我想我會咬下子彈,並實施我自己的枚舉器,而不是使用良率。 http://stackoverflow.com/questions/2308163/ability-to-reset-ienumerator-generated-using-yield-c – 2010-08-18 20:58:09

+0

你可以使用yield並使返回類型爲IEnumerable而不是IEnumerator,並移除IEnumerable的實現。然後設置DataContext來調用該方法。 – Kris 2010-08-18 21:13:05