WPF

2009-11-24 22 views
5

ile ObservableCollection ile Karma Grupları Kullanma Bir WPF uygulamasında öğeler listesini korumak için bir ListBox kullanıyorum. ListBox veri kaynağı bir ObservableCollection içinde sarılmış bir HashSet. Bir ICollectionWPF

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

... shackListing bir liste kutusu denetimi ve shackSet: yani Aşağıdaki kod var. Ancak, ilk öğenin eklenmesinden sonra shackSet'e bir şey eklediğimde, ListBox'ta birden çok öğe görüyorum. Yani, kümeye eklendiklerine bakılmaksızın yeni eklenen öğeler listeye ekleniyor gibi. Ben ıcollection # imzaları baktığımızda ekleyin:

void Add(T obj); 

... ve HashSet # Add:

bool Add(T obj); 

... Bu beni sarılı HashSets nerede yeni etkileyen bir hata var inanmak yol açar Eklenen öğeler ListBox'a eklensin, çünkü GözlemlenebilirKoleksiyonun nesnenin aslında toplama koleksiyonuna eklenmiş olup olmadığına dair bir yolu yoktur, çünkü ICollection # Add öğesinin dönüş türü geçersizdir. Bunu başka biri onaylayabilir mi?

cevap

8

Başka bir koleksiyonla yeni bir Gözlemlenebilir Koleksiyon oluşturduğunuzda, bu koleksiyonu silmiyorsunuz, geçirilen koleksiyonun tüm öğelerinin Gözlemlenebilir Veri'ye kopyalandığı yeni bir tane oluşturursunuz. DataBinding'ın tek amacı için bir ObservableCollection kullanmak istiyorsanız, daha fazla kendinizi düşünmeyin, WPF'de herhangi bir IEnumerable'a bağlayabilirsiniz. Bu beklenmedik bir şekilde WPF'nin her zaman doğru bir şekilde toplanan koleksiyondaki değişiklikleri almayacağı dezavantajına sahiptir. bu bir sorun ise muhtemelen kendi obeservable HashSet oluşturmak olurdu:

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

DÜZENLEME: OLARAK zaten sen INotifyCollectionChanged uygulamak için HashSet devralamaz işaret edilmiştir. Bununla birlikte, HashSet sınıfı için (Reflektör kullanarak) kodu incelerseniz, bu işlevselliği kendiniz taklit etmeniz çok zor olmalıdır.

+0

Tabii HashSet doğrudan bağlayabilir, ancak bir öğe eklenirse WPF fark etmez. Açıklama için –

+1

+1. Bununla birlikte, önerilen çözümle ilgili olarak, HashSet'ten miras almayı ve INotifyCollectionChanged'ı uygulamayı tercih ediyorum.Thomas'ın “HashSet” 'ten miras kalmaması ve 'HashSet' yöntemlerinin sanal olmadığı ve geçersiz kılınamayacağı için 'INotifyCollectionChanged' komutunu kullanamayacağınız hariç, –

+2

+1. “ICollection” u uygulamak zorunda kalacaksınız ve uygulamanızın, _wrap_ 'HashSet 'olması ve tüm mutasyon yöntemlerinde bildirimleri yükseltmesi gerekecektir. –

0

Bitbonk dediği gibi, ObservableCollection Hashset'i sarmalamaz, ancak bunun yerine öğelerini kopyalar.

bir gözlemlenebilir bitbonk cevabı gereğince How can I make an Observable Hashset in C# ?

+0

'a bir göz atın Microsoft'un özellik isteklerini göndermek için herhangi bir mekanizması var mı? Görünüşe göre, bir Gözlemlenebilir (Karma) Kümesi, .NET çerçevesinde olması gereken bir şeydir. –

+0

Elbette, Microsoft Connect'te. http://connect.microsoft.com/VisualStudio –

1

kontrol HashSet istiyorsanız, ama eklentiyi (T item) yöntemini geçersiz istedim ama bunu yapamazsınız, bu yüzden bir ekleme (T öğeyi) oluşturuldu yerine yöntemi: arkasında benim kod sonra

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

Ve: yukarıdaki olarak

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

Ben ListBoxes, listboxAvailableColumns var tha dizeleri bir listesi vardır t kullanıcı, ikinci liste kutusu listesine ekleyen listboxConsolidationColumns öğesini çift tıklayarak seçebilir. Hiçbir kopyaya izin verilmez ve bu tam olarak yukarıdaki gibi ObservableSetCollection ile mükemmel çalışır.

xaml

basitçe:

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