Pergunta

Estou usando uma caixa de listagem para manter uma lista de itens em um aplicativo WPF. A fonte de dados do ListBox é um hashset embrulhado em uma obserableCollection. ou seja, eu tenho o seguinte código:

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

... onde a lista de Shacklist é um controle da caixa de listagem e um Shackset em uma icollection. No entanto, sempre que adiciono qualquer coisa ao Shackset após a adição do primeiro item, vejo vários itens na caixa de listagem. ou seja, é como se os itens recém -adicionados estivessem sendo adicionados à lista, independentemente de serem adicionados ao conjunto. Quando olho para as assinaturas do icollection#add:

void Add(T obj);

... e hashset#add:

bool Add(T obj); 

... Isso me leva a acreditar que há um bug que afeta os hashsets embrulhados, onde itens recém -adicionados são adicionados à caixa de listagem, independentemente porque o ObservableCollection não tem como dizer se o objeto foi realmente adicionado à coleção subjacente porque o tipo de retorno de icollection# Add é nulo. Alguém mais pode confirmar isso?

Foi útil?

Solução

Quando você cria uma nova ObservableCollection com outra coleção, você não está envolvendo essa coleção, cria uma nova em que todos os itens da coleção aprovada são copiados para a ObservableCollection. Se você deseja usar uma observação ObservableCollection para o único objetivo de banco de dados, não procure mais, não procure mais, você pode se ligar a qualquer iEnumerable no WPF. Infelizmente, isso tem a desvantagem de que o WPF nem sempre capta corretamente as alterações na coleção Bound. Se esse é um problema, você provavelmente teria que criar seu próprio hashset obesertable:

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 já foi apontado, você não pode herdar do hashset para implementar o InotifyCollectionChanged. No entanto, se você olhar para o código (usando o refletor) para a classe HashSet, é bem simples, deve ser muito difícil imitar essa funcionalidade.

Outras dicas

De acordo com a resposta de Bitbonk, mas eu queria substituir o método Add (T Item), mas você não pode, então eu criei um método Append (T Item):

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

E então no meu código atrá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());
    }
}

No exposto, tenho duas caixas de listagem, o ListBoxavailableColumns, que possui uma lista de strings que o usuário pode selecionar clicando duas vezes, que adiciona a seleção à segunda caixa de lista, ListBoxConsolidationColumns. Nenhuma duplicata é permitida, e isso funciona perfeitamente com o ObservablesetCollection exatamente como acima.

O XAML é simplesmente:

<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 o Bitbonk disse, o ObservableCollection não envolve o hashset, mas copia seus elementos.

Se você quiser um hashset observável, check -out Como posso fazer um hashset observável em C#?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top