2009-05-08 3 views
2

ObservableCollection에서 이상한 일이 발생하고 있습니다.ObservableCollection 및 ListBoxItem DataTemplate 생성 문제

private readonly ObservableCollection<DisplayVerse> _display; 
private readonly ListBox _box; 

    private void TransferToDisplay() 
    { 
     double elementsHeight = 0; 

     _display.Clear(); 

     for (int i = 0; i < _source.Count; i++) { 
      DisplayVerse verse = _source[i]; 
      _display.Add(verse); 
      elementsHeight += CalculateItemsHeight(i); 
      if (elementsHeight + Offset > _box.ActualHeight) { 
       _display.RemoveAt(_display.Count - 1); 
       break; 
      } 
     } 
     MessageBox.Show(elementsHeight.ToString()); 
    } 

    private double CalculateItemsHeight(int index) 
    { 
     ListBoxItem lbi = _box.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem; 
     return lbi != null ? lbi.ActualHeight : 0; 
    } 

내가 여기서 뭘하려고하면 ObservableCollection에의 _display에 가서 얼마나 많은 항목을 제어 할 수 있습니다 :

나는 다음과 같은 코드가 있습니다. 이제이 for 루프 내에서 전체 요소 높이 (+ offset)가 목록 상자 자체보다 커질 때까지 요소가 추가된다는 것을 알 수 있습니다.

이제 이상하게 들리며, for 루프 이후에 elementsHeight는 0이됩니다. (CalculateItemsHeight는 lbi가 null이 아니더라도 모든 for 루프 반복에서 0을 반환합니다.) 데이터 템플릿에 정의 된 UI 요소가 만들어지지 않은 것처럼 보입니다 ...

아직.

이제 _display.Add (절) 뒤에 MessageBoxes를 넣으면 CalculateItemsHeight가 실제로 항목의 높이를 반환한다는 것을 알 수 있습니다.

for (int i = 0; i < _source.Count; i++) { 
    DisplayVerse verse = _source[i]; 
    _display.Add(verse); 
    MessageBox.Show("pause"); // <----- PROBLEM? 
    elementsHeight += CalculateItemsHeight(i); 
    if (elementsHeight + Offset > _box.ActualHeight) { 
     _display.RemoveAt(_display.Count - 1); 
     break; 
    } 
} 
MessageBox.Show(elementsHeight.ToString()); 

같이 I for 루프를 수정 한 후, 마지막 메시지 박스 실제로 모든 처리 요소의 실제 높이를 나타낸다.

내 질문에 - 실제로 UI 요소는 언제 생성됩니까? 그것은 그것이 MessageBox 표시하는 동안 어딘가에 이루어졌다 것 같습니다. 이 동작은 나에게는 꽤 이상한 일이며 어쩌면 스레딩과 관련이 있을지 모른다.

_display ObservableCollection에 추가하면 항목이 즉시 생성되지만 시각적 요소는 생성되지 않습니다 (나중에 추가되지만 정확히 언제 알지는 못합니다). 메시지 상자를 팝업하지 않고도이 동일한 동작을 수행하려면 어떻게해야합니까?

답변

0

은 (하나씩 로딩 항목 것처럼), 실제로 내 요구에 맞는이 순식간 다소 플리커 효과를 생성

를 해결했다.

요점은 항목 높이를 검색하기 전에 항목의 UI를 새로 고치는 것입니다.

public static void RefreshUI(this DependencyObject obj) 
    { 
     obj.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Loaded, (Action)delegate { }); 
    } 

그리고 높이를 검색하기 전에, 나는 UI를 새로 고침 :

난 확장 메서드를 만들었습니다.

private double CalculateItemsHeight(int index) 
    { 
     ListBoxItem lbi = _box.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem; 
     if (lbi != null) { 
      lbi.RefreshUI(); 
      return lbi.ActualHeight; 
     } 
     return 0; 
    } 
0

wpf 레이아웃 엔진은 레이아웃을 통과하지 못했고 패스를 정렬하지 않으므로 listboxitems에 아직 크기가 지정되지 않았습니다. 메시지 상자를 고수하면이 작업을 수행하는 백그라운드 스레드가 허용됩니다. 크기를보기 전에 항목에 대한 Measure() 호출을 강요하십시오.

+0

아니요. Measure()를 호출해도 문제가 해결되지 않았습니다. 내가 UI 스레드와 함께 성질해야한다고 생각하지만 UI 스레드 또는 호출하는 부분을 모르겠습니다. –

1

사실, 나는이 작업을 얻으려고 노력하고 있었고, 난 나를 위해 완벽하게 작동하는 ".UpdateLayout()"기능을 발견했다. 난 당신이 수직하고있는 것을 깨닫고 나는 수평을하고 있어요,하지만 여기 내 코드는, 그것은 아주 간단합니다

for (int i = 0; i < listOfItems.ItemsIn.Count; ++i) 
    { 
     //CalculateItemsHeight(i); 

     ListBoxItem abc = (lb.ItemContainerGenerator.ContainerFromItem(lb.Items[i]) as ListBoxItem); 
     abc.UpdateLayout(); 
     totalWidth += abc.ActualWidth; 
    } 

는 희망이 도움이!

관련 문제