Использование хэш-наборов с ObservableCollection с помощью WPF

StackOverflow https://stackoverflow.com/questions/1793109

Вопрос

Я использую ListBox для ведения списка элементов в приложении WPF.Источник данных ListBox представляет собой хэш-набор, заключенный в ObservableCollection.т.е. у меня есть следующий код :

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

...где shackListing - это элемент управления ListBox, а shackSet - в ICollection.Однако всякий раз, когда я добавляю что-либо в shackSet после добавления первого элемента, я вижу несколько элементов в ListBox.т. е. Это похоже на то, что недавно добавленные элементы добавляются в список независимо от того, добавлены ли они в набор.Когда я смотрю на подписи ICollection#Добавить :

void Add(T obj);

...и HashSet#Добавить :

bool Add(T obj); 

...это наводит меня на мысль, что есть ошибка, которая влияет на обернутые хэш-наборы, когда вновь добавленные элементы добавляются в ListBox независимо, потому что ObservableCollection не имеет способа определить, действительно ли объект был добавлен в нижележащую коллекцию, потому что возвращаемый тип ICollection#Add равен void .Кто - нибудь еще может это подтвердить ?

Это было полезно?

Решение

Когда вы создаете новую ObservableCollection с другой коллекцией, вы не оборачиваете эту коллекцию, вы создаете новую, в которой все элементы переданной коллекции копируются в ObservableCollection.Если вы хотите использовать ObservableCollection с единственной целью привязки к данным, не смотрите дальше, вы можете привязаться к любому IEnumerable в WPF.К сожалению, это имеет тот недостаток, что WPF не всегда корректно принимает изменения в связанную коллекцию.Если это проблема, вам, вероятно, придется создать свой собственный 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); 
    } 
}

Редактировать:КАК уже указывалось, вы не можете наследовать от HashSet для реализации INotifyCollectionChanged .Однако, если вы посмотрите на код (с использованием Reflector) для класса HashSet, он довольно прост, должно быть слишком сложно имитировать эту функциональность самостоятельно.

Другие советы

Согласно ответу bitbonk, но я хотел переопределить метод add (T item), но вы не можете, поэтому вместо этого я создал метод append (T item):

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

И затем в моем коде за:

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

В приведенном выше примере у меня есть два списка, listboxAvailableColumns, в которых есть список строк, которые пользователь может выбрать двойным щелчком мыши, который добавляет выделение во второй список, listboxConsolidationColumns.Дубликаты не допускаются, и это отлично работает с ObservableSetCollection точно так же, как описано выше.

xaml - это просто:

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

Как сказал bitbonk, ObservableCollection не переносит Hashset, а вместо этого копирует его элементы.

Если вам нужен Наблюдаемый хэш-набор, проверьте Как я могу создать Наблюдаемый хэш- набор в C # ?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top