2010-08-18 3 views
2

У меня есть класс, инкапсулирующий кучу коллекций. Я хотел бы привязать этот класс к списку для отображения элементов в коллекциях. Класс реализует IEnumerable. Когда отображается список, я ожидаю вызова метода IEnumerable.GetEnumerator. Однако не тогда, когда метод GetEnumerator использует ключевое слово yield. Однако, если я верну счетчик из коллекции List, он будет работать нормально, метод GetEnumerator вызывается каждый раз, когда отображается окно.Невозможно связать с реализацией IEnumerable с использованием результата

Что такого волшебного в перечислителе коллекции 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

Два решения, которые я нашел для меня, чтобы получить привязываемый источник данных, заключались в том, чтобы либо реализовать IList и IEnumerator, либо реализовать IEnumerable и INotifyCollectionChanged. Я решил, что источник данных реализует IEnumerable и INotifyCollectionChanged, поскольку он менее реализуется, и элементы не могут быть добавлены кодом клиента. –

ответ

2

Когда вы устанавливаете ItemsSource WPF обращается к нему через CollectionView, чтобы включить сортировку, группировку e.t.c. Представление разделяется так, что в вашем случае каждый элемент ItemsControl использует тот же Enumerator, но он никогда не перезагружается, поэтому появляется только последний элемент.

Если вы хотите поведение Snapshotting, существует несколько методов, но создание нового списка для каждого элемента ItemsControl является самым простым.

Если вы хотите, чтобы все они синхронизировались и обновлялись автоматически, см. ObservableCollection, который реализует INotifyCollectionChanged.

Возможно, вы также должны использовать общий интерфейс IEnumerable.

+0

Я также видел, что WPF использует collectionviews для доступа к данным. Почему счетчик из урона не сбрасывается, когда перечислитель из списка делает? Какой вид коллекций он создает, когда вы используете доход? –

+0

Нашел этот ответ, который не дает урона и сбрасывает. Спасибо, что направили меня в правильном направлении. Думаю, я просто укушу пулю и реализую свой собственный счетчик вместо использования урона. http://stackoverflow.com/questions/2308163/ability-to-reset-ienumerator-generated-using-yield-c –

+0

Вы можете использовать yield и иметь тип возвращаемого значения IEnumerable вместо IEnumerator и удалить реализацию IEnumerable. Затем установите DataContext для вызова этого метода. – Kris

Смежные вопросы