Pregunta

Estoy usando un cuadro de lista para mantener una lista de elementos en una aplicación de WPF. La fuente de datos ListBox es un HashSet envuelto en un ObservableCollection. es decir, tengo el siguiente código:

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

... donde shackListing es un control ListBox, y shackSet en un ICollection. Sin embargo, cada vez que añadir nada a shackSet después de la adición del primer artículo, veo varios elementos en el cuadro de lista. Es como decir que acaba de agregar artículos están siendo añadidos a la lista, independientemente de si están añaden al conjunto. Cuando miro a las firmas de ICollection # Añadir:

void Add(T obj);

... y HashSet # Añadir:

bool Add(T obj); 

... esto me lleva a creer que hay un error que afecta HashSets envueltos en donde los elementos recién añadidos se agregan al cuadro de lista sin tener en cuenta debido a que el ObservableCollection no tiene manera de saber si el objeto era en realidad añadió a la colección subyacente debido a que el tipo de retorno de ICollection # Añadir está vacío. Puede cualquiera otro confirmar esto?

¿Fue útil?

Solución

Cuando se crea un nuevo ObservableCollection con otra colección que no está envolviendo esa colección, se crea uno nuevo en el que todos los elementos de la colección pasado se copian en el ObservableCollection. Si desea utilizar una ObservableCollection con el único propósito de DataBinding, no busque más, puede unirse a cualquier IEnumerable en WPF. Esto desafortunadamente tiene el inconveniente de que no siempre será WPF cambios correctamente recogida a la colección encuadernada. Si esto es un problema que probablemente tiene que crear su propia hashset obeservable:

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: Como ya se ha señalado, no se puede heredar de HashSet para implementar INotifyCollectionChanged. Sin embargo, si nos fijamos en el código (con reflector) para la clase HashSet es bastante simple que debería ser demasiado difícil de imitar la funcionalidad de sí mismo.

Otros consejos

De acuerdo con la respuesta de bitbonk, pero quería anular el método add (T artículo), pero no se puede, así que creé un método append (T artículo) en su lugar:

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

Y luego en mi código detrás:

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());
    }
}

En lo anterior tengo dos cuadros de lista, listboxAvailableColumns, que tiene una lista de cadenas de caracteres que el usuario puede seleccionar haciendo doble clic, que se suma a la selección del segundo cuadro de lista, listboxConsolidationColumns. No se permiten duplicados, y esto funciona perfectamente con el ObservableSetCollection exactamente como anteriormente.

El XAML es simplemente:

<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>

Como dijo bitbonk, ObservableCollection no se ajusta al hashset pero las copias de sus elementos en su lugar.

Si quieres un observable hashset echa un vistazo a ¿Cómo puedo hacer un observable hashset en C #?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top