ObservableCollection で奇妙なことが起こっています。
次のコードがあります。
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 を返します) datatemplate で定義された UI 要素が作成されていないようです...
まだ。
ここで、_display.Add(verse) の後にいくつかの 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());
示されているように for ループを変更した後、最後の MessageBoxは実際に、処理されたすべての要素の実際の高さを示しています。
私の質問は、UI 要素が実際に作成されるのはいつですか? MessageBoxの表示中にどこかで行われたようです。この動作は私にとってはかなり奇妙です。スレッドと関係があるのかもしれませんが、よくわかりません。
_display ObservableCollection に追加すると、明らかにすぐにアイテムが作成されますが、その視覚要素は作成されません (ただし、後で追加されますが、正確な時期はわかりません)。メッセージ ボックスをポップアップ表示せずに、これと同じ動作を行うにはどうすればよいですか?