내 프로그램에서 백그라운드 작업자 스레드를 사용하여 파일을 엽니 다. 내 프로그램의 주요 구조는 데이터 바운드 TreeView
입니다. 진행중인 파일 읽기 중에 동적 TreeView
노드가 파일에서 읽을 때 TreeView
에 추가됩니다. 이 TreeView
노드는 UICollections
(ObservableCollection<T>
에서 상속 된 사용자 정의 클래스) 컨테이너에 바인딩됩니다. 이 유형의 CollectionViews
이 배경 작업자 스레드에서 SourceCollections
을 변경하지 않았는지 확인하기 위해 UICollection<T>
클래스를 생성했습니다. 저는 에있는 IsNotifying
이라는 속성을 false
으로 변경하여이 작업을 수행합니다.OnCollectionChanged 및 백그라운드 스레드 문제
내 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));
}
}
나는 배경 작업자 스레드에서 UICollections
을 추가해야 내 제어 구조,이 UICollection<T>
을 구현하는 데 문제가 말했다되고.
, 내 프로그램 이동 다음과 같이 배경 작업자 스레드에서
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
로 설정해야한다는 것입니다. 이미 알려진 컬렉션에 대해서는이 작업을 수행하는 데 아무런 문제가 없지만 동적 인 작업에 대해서는 문제가 발생합니다. 내 배경 작업자 스레드가하는 일의
샘플 : UIThread에서
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...
}
방법 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>
클래스에있는 것 같습니다.
안녕하세요. 마이크. 당신이 내 게시물을 아주 잘 이해하는 것처럼 들리네. 나는 그것이 길다는 것을 알고 있지만 가능한 한 명확히하려고 노력했다. 내 컬렉션을 변경하기 위해 UIThread로 이동할 때마다 백그라운드 스레드를 멈추도록 권장합니까? –
UI 스레드가 참조하는 백그라운드 스레드의 컬렉션을 수정할 수 없다는 말입니다. 일반적으로 할 수있는 최선의 방법은 원본 컬렉션의 복사본을 만들고 복사본에서 배경을 수정 한 다음 완료되면 UI 스레드로 다시 정렬하여 원래 컬렉션을 수정 된 복사본으로 바꿉니다. UI 스레드와 백그라운드 스레드 모두에서 수정 작업을 수행하게되면 상황이 더욱 복잡해지며 두 가지 변경 사항을 조정할 방법이 필요하지만 UI 스레드에서 수행해야합니다 게다가. –
감사합니다. @MikeStrobel. 추가해야 할 컬렉션을 모두 큐에 넣고 백그라운드 작업자 스레드를 닫은 후 추가하는 것이 더 쉬울까요? –