2009-11-24 4 views
5

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

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

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

ответ

8

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

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

+0

Конечно, вы можете связать непосредственно с HashSet, но если добавить элемент WPF не заметит. –

+1

+1 для объяснения. Однако, в отношении предлагаемого решения, я бы скорее наследовал от HashSet и реализовал INotifyCollectionChanged ... –

+2

+1 к тому, что сказал Томас, за исключением того, что вы не можете наследовать от «HashSet», а также реализовать «INotifyCollectionChanged», поскольку методы «HashSet» не являются виртуальными и не могут быть переопределены. Вам придется реализовать 'ICollection', и ваша реализация должна будет _wrap_' HashSet' и повышать уведомления обо всех методах мутирования. –

0

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

Если вы хотите, чтобы Наблюдаемое HashSet проверить How can I make an Observable Hashset in C# ?

+0

Есть ли у Microsoft механизм отправки запросов функций? Мне кажется, что набор Observable (Hash) - это то, что уже должно быть в платформе .NET. –

+0

Несомненно, в Microsoft Connect. http://connect.microsoft.com/VisualStudio –

1

В соответствии с ответом bitbonk, но я хотел, чтобы переопределить надстройку (T элемент) метод, но вы не можете, так что я создал добавление (T элемент) метод вместо:

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

в выше у меня есть два ListBoxes, listboxAvailableColumns, который содержит список строк тха t пользователь может выбрать двойным щелчком, который добавляет выделение ко второму списку, 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> 

 Смежные вопросы

  • Нет связанных вопросов^_^