J'ai une classe encapsulant un groupe de collections. Je voudrais lier cette classe à une liste pour afficher les éléments dans les collections. La classe implémente IEnumerable. Lorsque la liste est affichée, je m'attends à ce que la méthode IEnumerable.GetEnumerator soit appelée. Ce n'est cependant pas le cas lorsque la méthode GetEnumerator utilise le mot-clé yield. Toutefois, si je renvoyais l'énumérateur d'une collection List, cela fonctionnerait correctement, la méthode GetEnumerator est appelée chaque fois qu'une fenêtre est affichée.Impossible de lier l'implémentation IEnumerable en utilisant le rendement
Qu'y a-t-il de si magique dans l'énumérateur d'une collection de List ??? Quelle est la bonne interface à implémenter pour permettre à un objet WPF d'obtenir des snapshots (mises à jour non nécessaires) ??? Est IList celui à utiliser ??? Le code ci-dessous ajoute un horodatage chaque fois qu'une nouvelle fenêtre est ouverte. Cependant, la zone de liste ne montre jamais plus d'un horodatage, qui est le nombre de timestamps le premier (et le seul temps) GetEnumerator est appelé. Le nombre augmente, donc les horodateurs sont ajoutés. Si vous changez la méthode GetEnumerator pour renvoyer l'énumérateur de la collection de listes, la méthode GetEnumerator est appelée à chaque fois qu'une nouvelle fenêtre est ouverte.
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>
code
derrière:
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>();
}
}
Les deux solutions que j'ai trouvées en travaillant pour obtenir une source de données pouvant être liée consistaient soit à implémenter IList et IEnumerator, soit à implémenter IEnumerable et INotifyCollectionChanged. J'ai décidé de faire en sorte que la source de données implémente IEnumerable et INotifyCollectionChanged, car elle est moins implémentable et les éléments ne peuvent pas être ajoutés par le code client. –