2011-01-12 7 views
3

내 응용 프로그램에서는 ItemsSource가 변경된 직후 ItemsCollection의 내용을 가져와야합니다. 또는 최소한 내용을 시각적으로 그릴 가능성이 있기 전에.WPF에서 가능한 경쟁 조건 ItemsCollection.ItemContainerGenerator

void UserControl_Loaded(object sender, EventArgs eventArgs) { 
    this.itemsControl.ItemsSource = GetItemsSource(); 

    int ctrIndex = 0; 
    DependencyObject container; 
    while((container = this.itemsControl.ItemContainerGenerator. 
     ContainerFromIndex(ctrIndex++)) != null) { 

     DoSomething(VisualTreeHelper.GetChild(container, 0)); 
    } 
} 

문제는 해봐요가 호출되는 시점에서, VisualTreeHelper.GetChildrenCount(container)의 값이 0입니다 것입니다 :

나는 다음에 가까운 무언가를 테스트했다. 이 코드가 나중에 Button.Click 이벤트 발생에 대한 응답으로 나중에 호출 될 경우 VisualTreeHelper.GetChildrenCount이 예상 값이며 코드가 작동 할 수 있습니다.

추신. 또한 익명 함수 내부에서 while 루프를 수행하려고 시도했습니다.

this.itemsControl.ItemContainerGenerator.ItemsChanged += (_sender, _ea) => { 
    int ctrIndex = 0; 
    DependencyObject container; 
    while((container = this.itemsControl.ItemContainerGenerator. 
     ContainerFromIndex(ctrIndex++)) != null) { 

     DoSomething(VisualTreeHelper.GetChild(container, 0)); 
    } 
}; 

동작은 슬프게도 동일합니다.

난 당신이 생성 된 콘텐츠를 통해 이동해야한다 얼마나 많은 농구 믿을 수 없다

편집.

생성 된 컨테이너를 안전하게 캡처 할 수있는 가장 빠른 순간을 찾았습니다. 그러나, 나는 아직도 그 컨테이너 안의 생성 된 내용에 대해 nil을 설정하고있다. 다음 관찰 :

this.itemsControl.ItemContainerGenerator.StatusChanged += new EventHandler(StatusChanged); 

void StatusChanged(object sender, EventArgs e) { 
    var cg = this.itemsControl.ItemContainerGenerator; 
    if(cg.Status == GeneratorStatus.ContainersGenerated && cg.ContainerFromIndex(0) != null) { 
    DoStuff(); 
    } 
} 

를 점 DoStuff에서()가 호출, ContainerFromIndex에서 반환 된 용기는 null이 아니다. 그러나 VisualTreeHelper.GetChildrenCount(container)은 0입니다. 저는 여전히 누군가가 이것을 해결했는지 알고 싶습니다.

+0

독자에게 ItemsControl 내에서 생성 된 내용을 참조 할 수있는 확실한 방법이 없다는 점을 알아 보았습니다. 모든 비용을 들이지 않고 이것을 피하십시오. – Kivin

답변

0

문제는 컬렉션이 변경되는 동안 컬렉션을 반복 할 수 없다는 것입니다. 이 문제를 극복하는 한 가지 방법은 컨트롤의 ItemsSource를 반복하는 대신 데이터가 채워진 후 ItemsSource 개체를 직접 보는 것입니다. MVVVM 패턴을 사용하는 경우 ViewModel에서 컬렉션 속성 (컨트롤의 ItemsSource에 바인딩하는 속성)을 채우고 데이터가 데이터베이스/서비스에서 반환되는지 검사 할 수 있어야합니다.

+0

내가 잘못 본게 아니라면, ItemsSource를 보면이 문제가 해결되지 않을 것입니다.ItemsSource는 Control_Loaded 이벤트의 ItemsSource에 적용되는 데이터라는 가정하에 있습니다. 이 데이터는 ItemsSource에 바인딩 된 후에는 관련이 없습니다. – Kivin

3

몇 분 전에 같은 문제가 발생했습니다. 약간의 차이점은 항목 컨테이너의 정확한 위치 및 크기 정보가 필요하다는 것입니다. 나는이라는 StatusChanged 이벤트를 들으려고 시도했으며, 상태가 ContainersGenerated이되었고 컨테이너가 실제로 생성되었지만 아직 배치되지 않았 음을 발견했습니다.

그래서 나는 정말 무언가를했습니다. ItemContainerGenerator의 상태가 ContainersGenerated되었다 동안 우선은 항목 컨테이너가 배치되어 있는지 나는이 _updatePending 플래그를 확인하기 위해, 매우 자주 발생 것 ItemsControlLayoutUpdated 이벤트를 처리하고, 플래그, 말, _updatePending을 설정

var firstContainer = this.ItemsContainer.ItemContainerGenerator.ContainerFromIndex(0) as FrameworkElement; 
if (_updatePending 
    && firstContainer != null 
    && firstContainer.IsLoaded) 
{ 
    // do stuff 
    _updatePending = false; 
} 

이것은 잔인하지만 어떻게 든 효과적입니다.

관련 문제