2011-01-12 73 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)); 
    } 
} 

的問題是,在點DoSomething的叫的VisualTreeHelper.GetChildrenCount(container)0。如果此代碼在稍後的時間點被調用 - 例如響應Button.Click事件觸發,則VisualTreeHelper.GetChildrenCount是預期值,並且代碼可能會起作用。

PS。我也試圖在匿名函數中進行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)); 
    } 
}; 

行爲是相同的,令人遺憾的是。

編輯

我不能相信你一定有多少籃球對生成的內容通過跳躍。

我相信我已經找到了可以安全捕獲生成的容器的最早時刻。但是,我仍然對這些容器中生成的內容無所作爲。注意以下事項:

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返回容器不爲空。但是,VisualTreeHelper.GetChildrenCount(container)是0.我仍然非常想知道是否有人解決了這個問題。

+0

對於讀者,我會指出,我發現絕對沒有可靠的方法來引用ItemsControl中生成的內容。不惜一切代價避免這種情況。 – Kivin 2011-01-24 14:21:04

回答

0

問題是,您無法在正在更改的集合上迭代集合。解決這個問題的一種方法是在數據填充後直接查看ItemsSource對象,而不是試圖迭代控件上的ItemsSource。如果您使用的是MVVVM模式,則應該能夠在ViewModel中填充集合屬性(您綁定到控件的ItemsSource的屬性),並檢查數據是否從數據庫/服務返回。

+0

除非我錯了,否則看着ItemsSource不會解決這個問題。我假設ItemsSource將==在Control_Loaded事件中應用於ItemsSource的數據。這些數據綁定到ItemsSource後無關緊要。 – Kivin 2011-01-12 19:28:21

3

幾分鐘前我遇到了同樣的問題。一些小的區別是,我需要物品容器的準確定位和尺寸信息。我嘗試着試圖聽ItemContainerGeneratorStatusChanged事件,最後發現當狀態變成ContainersGenerated並且容器確實生成時,它們還沒有佈置。

所以我做了一件非常粗糙的事情。首先,我設置一個標誌,也就是說,_updatePending,而ItemContainerGenerator的狀態成爲ContainersGenerated,然後我處理的LayoutUpdated事件ItemsControl,這將觸發相當頻繁,檢查_updatePending標誌和物品的容器是否佈局:

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

這是殘酷的,但以某種方式有效。