2017-03-09 85 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

相关问题