2017-03-09 88 views
0

這聽起來似乎是一個簡單的問題,但我找不到任何在線工作。我正在使用PRISM,在我離開之前我就走了一步,永遠不會回到這個框架。這裏的原因:如何添加項目到ObservableCollection?

我很ObservableCollection如果我給你一個列表,並忘掉它基本上工作。但這不是ObservableCollection的目標,對吧?它改變了。所以,這裏的集合:

<DataGrid ItemsSource="{Binding Items, Mode=TwoWay}" AutoGenerateColumns="True" /> 

    private ObservableCollection<Item> _items = new ObservableCollection<Item>(); 
    public ObservableCollection<Item> Items 
    { 
     get { return _items; } 
     set { SetProperty(ref _items, value); } 
    } 

所以,這裏有雲:

 Items = InitializeItems(); // Works great! 
     Items.Add(new Item() { ItemId = 1 }); // Also works 

但後來..

 for (int i = 1; i < 10; i++) 
     { 
      Items.Add(new Item() { ItemId = i }); 
     } 

失敗。有時候,有例外:

'System.InvalidOperationException' 類型的未處理的異常發生在PresentationFramework.dll其他信息:一個 ItemsControl的是帶項目源不一致。

AddRange()

 Task.Factory.StartNew(() => 
     { 
      Items = InitializeItems(); // Works great! 
      Items.Add(new Item() { ItemId = 1 }); // Also works 
      for (int i = 1; i < 10; i++) 
      { 
       Items.Add(new Item() { ItemId = i }); 
      } 
     }); 

我甚至創建擴展方法:

public static class ObservableCollectionExtensions 
{ 
    public static void AddRange<T>(this ObservableCollection<T> data, List<T> range) 
    { 
     if (range == null) throw new ArgumentNullException("range"); 
     foreach (var i in range) data.Add(i); 

     // How can I force ObservableCollection to update?! 

    } 
} 

EHH ..我在做什麼錯算了吧..

一切都在獨立線程中完成的?我正在更換ObservableCollection。所以,每次我想添加新的項目時,我都必須從舊的和新的創建新的集合並分配給ObservableCollection?因爲只有賦值運算符爲我工作:(

感謝您的幫助!

+0

是否有可能有一個重複的'ItemId'爲'1'導致與ObservableCollection無關的問題? –

+1

當ObservableCollection' propery在View中綁定時,它應該總是隻在UI Thread中更新。否則它會給STA線程錯誤。 –

+0

在WPF中,PropertyChanged事件會自動封送到UI線程,但INotifyCollectionChanged不是這種情況。如果你想修改ObservableCollection,你必須確保你的修改是在UI線程上完成的,否則會有異常。 –

回答

2

一個ItemsControl是帶項目源不一致

意味着DataGrid中已檢測到它持有不匹配來源的項目,這樣當您更改源的情況新的集合與出強制刷新上的項目控制

解決這一問題的最簡單的方法是改變

private ObservableCollection<Item> _items = new ObservableCollection<Item>(); 
public ObservableCollection<Item> Items 
{ 
    get { return _items; } 
    set { SetProperty(ref _items, value); } 
} 

public ObservableCollection<Item> Items{get;}= new ObservableCollection<Item>(); 

,或者如果你沒有使用C#6

private ObservableCollection<Item> _items = new ObservableCollection<Item>(); 
public ObservableCollection<Item> Items 
{ 
    get { return _items; } 
} 

這意味着你不能改變集合了只有它的內容

如果你真的需要多線程,然後我想補充以下代碼

private Dispatcher dispatcher = Dispatcher.CurrentDispatcher; 

這對y是至關重要的OU需要當時的類創建當前不叫它

的一個CurrentDispatcher然後調用

dispatcher.Invoke(()=>Items.Add(item)); 

,因爲這將確保只有創建集合線程改變它

這裏是一個完整的工作示例

public class VM 
{ 
    public VM() 
    { 
     AddItems = new DelegateCommand(() => Task.Run(()=> 
      Parallel.ForEach(
       Enumerable.Range(1,1000), 
       (item) => dispatcher.Invoke(() => Items.Add(item)) 
      )) 
     ); 
    } 
    public ObservableCollection<int> Items { get; } = new ObservableCollection<int>(); 
    private Dispatcher dispatcher = Dispatcher.CurrentDispatcher; 

    public DelegateCommand AddItems { get; } 
} 

與下面的XAML

<DockPanel > 
    <Button DockPanel.Dock="Top" Content="Add" Command="{Binding AddItems, Mode=OneWay}" /> 
    <ListView ItemsSource="{Binding Items}"/> 

</DockPanel> 
+0

我正在查找'dispatcher.Invoke((=)Items.Add(項目));'謝謝。抱歉,延遲接受你的答案。 –

3

代碼中的幾個問題。

a)使用ObservableCollection時,不要再次初始化它。創建一個實例並向其添加或刪除項目。所以你的代碼變成了。

private ObservableCollection<Item> _items = new ObservableCollection<Item>(); 
public ObservableCollection<Item> Items 
{ 
    get { return _items; } 
} 

或本(如果你的VS支持)

public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>(); 

和添加項目

foreach (var item in InitializeItems()) Items.Add(item); 
Items.Add(new Item() { ItemId = 1 }); 
for (int i = 1; i < 10; i++) 
{ 
    Items.Add(new Item() { ItemId = i }); 
} 

b)你說

一切都在單獨的線程中完成的:

切勿從非UI線程更新UI綁定屬性。對於數據獲取,您可以使用非UI線程,但是一旦檢索到數據,就只能在UI線程的屬性中添加/更新數據。

+0

A)是正確的。 B),不是那麼多。 INPC綁定會自動編組到UI線程中。 INCC綁定並不幸運。所以你必須使用Dispatcher來更新OC。 – Will

+0

@願意如果您使用的是.NET 4.5或更新的版本,您也可以擁有自動編組功能。從另一個如何設置它的問題看[這個答案](http://stackoverflow.com/questions/2091988/how-do-i-update-an-observablecollection-via-a-worker-thread)。 –

+0

@ScottChamberlain不,你就是這麼做的 - 使用調度器。 4.5中沒有新東西。 – Will

相關問題