2009-11-24 26 views
5

我使用ListBox來維護WPF應用程序中的項目列表。 ListBox數據源是一個包裝在ObservableCollection中的HashSet。即,我有以下代碼:通過WPF使用帶有ObservableCollection的HashSet

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

...其中shackListing是一個ListBox控件,並在ICollection中設置ShackSet。但是,無論何時在添加第一個項目之後向ShackSet添加任何內容,我都會在ListBox中看到多個項目。即這就像新添加的項目被添加到列表中,而不管它們是否被添加到集合中。當我看的ICollection的#簽名地址:

void Add(T obj); 

...和HashSet的#地址:

bool Add(T obj); 

...這使我相信有一個影響包裹HashSets其中新的錯誤添加的項目被添加到列表框中,無論因爲ObservableCollection無法確定對象是否實際添加到下層集合,因爲ICollection#Add的返回類型是無效的。其他人可以證實這一點嗎?

回答

8

當你創建你是不是包裝該集合另一個集合了新的ObservableCollection,您創建一個新的,其中傳遞的集合的所有項目都複製到的ObservableCollection。如果您希望將ObservableCollection用於DataBinding的唯一目的,那麼請不要再觀察,您可以將其綁定到WPF中的任何IEnumerable。這種不幸的缺點是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); 
    } 
} 

編輯: AS已經已經指出的那樣,你不能從HashSet的繼承來實現INotifyCollectionChanged。但是,如果您查看HashSet類的代碼(使用Reflector),它非常簡單,您應該很難親自模擬該功能。

+0

當然您也可以直接綁定到HashSet的,但如果添加一個項目WPF不會注意到。 –

+1

+1的解釋。但是,關於建議的解決方案,我寧願從HashSet繼承並實現INotifyCollectionChanged ... –

+2

對托馬斯說的+1,除了你不能繼承'HashSet'並且也實現'INotifyCollectionChanged',因爲'HashSet'方法不是虛擬的,不能被覆蓋。你必須實現'ICollection',你的實現將不得不_wrap_'HashSet'並且引發所有變異方法的通知。 –

0

正如bitbonk所說,ObservableCollection不會包裝Hashset,而是複製它的元素。

如果你想要一個可觀察的Hashset退房How can I make an Observable Hashset in C# ?

+0

微軟是否有任何提交功能請求的機制?在我看來,Observable(哈希)集合應該已經在.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()); 
    } 
} 

在上面我有兩個列表框,listboxAvailableColumns,其中有串THA列表用戶可以通過雙擊進行選擇,這會將選擇添加到第二個列表框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> 
相關問題