在我的程序中,我使用后台工作线程打开文件。我的程序的主要结构是数据绑定TreeView
。在文件读入过程中,动态TreeView
节点在从文件TreeView
中读入时被添加到。TreeView
我提到的这些节点绑定到称为UICollections
(继承自的自定义类ObservableCollection<T>
)的容器。我创建了这个UICollection<T>
类,以确保CollectionViews
这种类型永远不会SourceCollections
从后台工作线程中更改。我通过更改UICollection
被调用的属性IsNotifying
来做到这一点false
。
我的UICollection<T>
班级:
public class UICollection<T> : ObservableCollection<T>
{
public UICollection()
{
IsNotifying = true;
}
public UICollection(IEnumerable<T> source)
{
this.Load(source);
}
public bool IsNotifying { get; set; }
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (IsNotifying)
base.OnPropertyChanged(e);
}
//Does not raise unless IsNotifying = true
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (IsNotifying)
base.OnCollectionChanged(e);
}
//Used whenever I re-order a collection
public virtual void Load(IEnumerable<T> items)
{
if (items == null)
throw new ArgumentNullException("items");
this.IsNotifying = false;
foreach (var item in items)
this.Add(item);
//ERROR created on this line because IsNotifying is always set to true
this.IsNotifying = true;
this.Refresh();
}
public Action<T> OnSelectedItemChanged { get; set; }
public Func<T, bool> GetDefaultItem { get; set; }
public void Refresh()
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
话虽如此,我在UICollection<T>
用我的控制结构实现这一点时遇到了问题,这涉及UICollections
从后台工作线程添加。
为清楚起见,我的程序移动如下:
Is a file being opened?: YES -> go into Background worker thread
在后台工作线程中:(
Do we need to create new UICollections?: YES -> go to method in UIThread that does so
根据需要迭代)关闭线程。
需要理解的主要概念是,如果后台工作线程打开,则UICollection.IsNotifying
必须设置为。false
对于已经知道的集合,我这样做没有问题,但对于我遇到问题的动态集合。
我的后台工作线程所做的示例:
private void openFile()
{
//Turn off CollectionChanged for known Collections
KnownCollections1.IsNotifying = false;
KnownCollections2.IsNotifying = false; //... and so on
//Do we need to create new collections? YES -> Call to AddCollection in UIThread
//Refresh known collections
App.Current.Dispatcher.BeginInvoke((Action)(() => KnownCollections1.Refresh()));
App.Current.Dispatcher.BeginInvoke((Action)(() => KnownCollections2.Refresh())); //... and so on
//If new collections exist find them and refresh them...
}
UIThread 中将集合添加到的方法TreeView
:
public void AddCollection(string DisplayName, int locationValue)
{
node.Children.Add(CreateLocationNode(displayName, locationValue)); //Add to parent node
for (int i = 0; i < node.Children.Count(); i++)
{
//make sure IsNotifying = false for newly added collection
if (node.Children[i].locationValue == locationValue)
node.Children[i].Children.IsNotifying = false;
}
//Order the collection based on numerical value
var ordered = node.Children.OrderBy(n => n.TreeView_LocValue).ToList();
node.Children.Clear();
node.Children.Load(ordered); //Pass to UICollection class -- *RUNS INTO ERROR*
}
有了所有这些,将会发生两件事之一......如果我注释掉该行this.IsNotifying = true;
,则会出现异常,OnCollectionChanged
因为它在后台线程打开时被引发。如果我保持原样,集合将永远不会反映在视图中,因为OnCollectionChanged
永远不会被提升,通知视图。我需要做什么才能允许创建这些集合而不会遇到这些错误?我猜问题出在我的AddCollection()
函数或UICollection<T>
课堂上。