Question

J'utilise un ListBox pour maintenir une liste d'éléments dans une application WPF. La source de données ListBox est un HashSet enveloppé dans un ObservableCollection. à-dire, je le code suivant:

this.shackSet = new ObservableCollection<Shack>(new HashSet<Shack>());
this.shackListing.ItemsSource = this.shackSet;

... où shackListing est un contrôle ListBox et shackSet dans un ICollection. Cependant, chaque fois que j'ajouter quelque chose à shackSet après l'ajout du premier élément, je vois plusieurs éléments dans la liste. Il est comme par exemple les éléments nouvellement ajoutés sont s'ajoutés à la liste indépendamment du fait qu'ils sont ajoutés à l'ensemble. Quand je regarde les signatures de ICollection # Ajouter:

void Add(T obj);

... et HashSet # Ajouter:

bool Add(T obj); 

... cela me porte à croire qu'il ya un bug qui affecte enveloppées HashSet où les éléments nouvellement ajoutés sont ajoutés à la zone de liste quelle que soit parce que le ObservableCollection n'a aucun moyen de dire si l'objet a été effectivement ajouté à la collection underlaying parce que le type de retour de ICollection # Ajouter est vide. Quelqu'un peut-il confirmer cette autre?

Était-ce utile?

La solution

Lorsque vous créez un nouveau ObservableCollection avec une autre collection vous n'êtes pas envelopper cette collection, vous créez un nouveau où tous les articles de la collection passée sont copiés dans le ObservableCollection. Si vous souhaitez utiliser un ObservableCollection dans le seul but de DataBinding, ne cherchez pas plus loin, vous pouvez lier à tout IEnumerable dans WPF. Cela a unfortuantely l'inconvénient que WPF ne sera pas toujours des changements attrapez correctement à la collection liée. Si cela est un problème que vous auriez probablement créer votre propre obeservable HashSet:

public class ObservableHashSet<T> : ObservableCollection<T>  
{ 
    protected override void InsertItem(int index, T item) 
    { 
        if (Contains(item)) 
        {
            throw new ItemExistsException(item); 
        }
        base.InsertItem(index, item); 
    } 

    protected override void SetItem(int index, T item) 
    { 
        int i = IndexOf(item); 
        if (i >= 0 && i != index)
        {
             throw new ItemExistsException(item); 
        }       
        base.SetItem(index, item); 
    } 
}

EDIT: Comme il a déjà a été signalé, vous ne pouvez pas hériter de HashSet à mettre en œuvre INotifyCollectionChanged. Toutefois, si vous regardez le code (en utilisant réflecteur) pour la classe HashSet il est assez simple, il devrait être trop difficile à imiter cette fonctionnalité vous-même.

Autres conseils

Selon la réponse de bitbonk, mais je voulais passer outre la méthode add (T article), mais vous ne pouvez pas, donc je créé une méthode append (T item) au lieu:

public class ObservableSetCollection<T> : ObservableCollection<T> {
    public void Append(T item) {
        if (Contains(item)) return;
        base.Add(item);
    }
}

Et puis dans mon code derrière:

public partial class MainWindow : Window {
    private ObservableSetCollection<string> consolidationHeaders;

    public MainWindow() {
        InitializeComponent();
        initialize();
    }

    private void initialize() {
        consolidationHeaders = new ObservableSetCollection<string>();
        listboxConsolidationColumns.ItemsSource = consolidationHeaders;
    }

    .
    .
    .


    private void listboxAvailableColumns_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
        consolidationHeaders.Append(listboxAvailableColumns.SelectedValue.ToString());
    }

    private void listboxConsolidationColumns_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
        consolidationHeaders.Remove(listboxConsolidationColumns.SelectedValue.ToString());
    }
}

Dans ce qui précède, j'ai deux listboxes, listboxAvailableColumns, qui a une liste de chaînes que l'utilisateur peut sélectionner en double-cliquant, qui ajoute la sélection à la deuxième zone de liste, listboxConsolidationColumns. Aucun doublon sont autorisés, et cela fonctionne parfaitement avec le ObservableSetCollection exactement comme ci-dessus.

Le XAML est simplement:

<Grid Margin="5,5,5,5">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Grid.Column="0" Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Available Columns"/>
    <Label Grid.Row="0" Grid.Column="1" Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Consolidation Columns"/>
    <ListBox  Grid.Row="1" Grid.Column="0" Name="listboxAvailableColumns" MouseDoubleClick="listboxAvailableColumns_MouseDoubleClick" />
    <ListBox  Grid.Row="1" Grid.Column="1" Name="listboxConsolidationColumns" MouseDoubleClick="listboxConsolidationColumns_MouseDoubleClick" />
</Grid>

Comme bitbonk dit ObservableCollection ne pas envelopper la HashSet mais des copies de ses éléments à la place.

Si vous voulez un HashSet Observable consulter Comment puis-je faire un HashSet observable en C #?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top