2011-09-09 47 views
10

短版當列表框ScrollIntoView使用具有GroupDescriptions CollectionViewSource(即IsGrouping == TRUE)

我想當選擇被改變爲ListBox項滾動到視圖。

龍版

我有綁定到CollectionViewSourceGroupDescriptionItemsSource一個ListBox,如下面的例子。

<Window.Resources> 
    <CollectionViewSource x:Key="AnimalsView" Source="{Binding Source={StaticResource Animals}, Path=AnimalList}"> 
     <CollectionViewSource.GroupDescriptions> 
      <PropertyGroupDescription PropertyName="Category"/> 
     </CollectionViewSource.GroupDescriptions> 
    </CollectionViewSource> 
</Window.Resources> 

<ListBox x:Name="AnimalsListBox"ItemsSource="{Binding Source={StaticResource AnimalsView}}" ItemTemplate="{StaticResource AnimalTemplate}" SelectionChanged="ListBox_SelectionChanged"> 
    <ListBox.GroupStyle> 
     <GroupStyle HeaderTemplate="{StaticResource CategoryTemplate}" /> 
    </ListBox.GroupStyle> 
</ListBox> 

代碼隱藏文件中有SelectionChanged事件。

public List<Animal> Animals { get; set; } 

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    ListBox control = (ListBox)sender; 
    control.ScrollIntoView(control.SelectedItem); 
} 

現在。如果我將AnimalsListBox.SelectedItem設置爲當前不可見的項目,我想讓它在視圖中滾動。這是它變得棘手的地方,因爲ListBox是羣組(IsGrouped屬性是true),調用ScrollIntoView失敗。

System.Windows.Controls.ListBox via Reflector。請注意0​​中的base.IsGrouping

public void ScrollIntoView(object item) 
{ 
    if (base.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) 
    { 
     this.OnBringItemIntoView(item); 
    } 
    else 
    { 
     base.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(this.OnBringItemIntoView), item); 
    } 
} 

private object OnBringItemIntoView(object arg) 
{ 
    FrameworkElement element = base.ItemContainerGenerator.ContainerFromItem(arg) as FrameworkElement; 
    if (element != null) 
    { 
     element.BringIntoView(); 
    } 
    else if (!base.IsGrouping && base.Items.Contains(arg)) 
    { 
     VirtualizingPanel itemsHost = base.ItemsHost as VirtualizingPanel; 
     if (itemsHost != null) 
     { 
      itemsHost.BringIndexIntoView(base.Items.IndexOf(arg)); 
     } 
    } 
    return null; 
} 

問題

  1. 任何人能解釋爲什麼它在使用分組工作?
    • ItemContainerGenerator.ContainerFromItem總是返回null,即使它的狀態狀態表明所有容器都已生成。
  2. 我怎樣才能實現滾動查看當使用分組?

回答

8

我找到了解決我的問題的方法。我確定我不是第一個遇到這個問題的人,所以我繼續搜索StackOverflow尋找解決方案,並且我偶然發現了David about how ItemContainerGenerator works with a grouped list的答案。

David的解決方案是延遲訪問ItemContainerGenerator直到之後的渲染過程。

我已經實施了這個解決方案,稍後我會詳細介紹一些變化。

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    ListBox control = (ListBox)sender; 

    if (control.IsGrouping) 
    { 
     if (control.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) 
       Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(DelayedBringIntoView)); 
     else 
       control.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; 
    } 
    else 
     control.ScrollIntoView(control.SelectedItem); 
} 

private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) 
{ 
    if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) 
     return; 

    ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; 
    Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(DelayedBringIntoView)); 
} 

private void DelayedBringIntoView() 
{ 
    var item = ItemContainerGenerator.ContainerFromItem(SelectedItem) as ListBoxItem; 
    if (item != null) 
     item.BringIntoView(); 
} 

變化:

  • 只使用ItemContainerGenerator方法時,它IsGroupingtrue,否則繼續使用默認ScrollIntoView
  • 檢查ItemContainerGenerator是否已準備就緒,如果是這樣的調度行動,否則聽取ItemContainerGenerator狀態改變..這很重要,如果它準備好,那麼StatusChanged事件將永遠不會觸發。
+0

您應該將答案更改爲正確的答案,而不是上面的答案。 – Valentein

+0

@Valentein:我已經改變了標記的答案。但作爲[crazyarabian](http://stackoverflow.com/a/7375646/73025)建議確實幫助我診斷問題,如果您使用我最終的解決方案,那麼最好**這兩個答案**。 – Dennis

+0

使用.NET 4.5.1和MVVM,您可以使用一種行爲來執行此操作。這種行爲在兩種情況下均有效,因爲它已經很晚了。 – Kelly

3
  1. 的開箱VirtualizingStackPanel不支持虛擬化分組收集意見。當在一個ItemsControl中呈現分組的集合時,每個組作爲一個整體是一個項目,而不是集合中的每個項目,這導致滾動到每個組標題而不是每個項目的「生澀」。

  2. 您可能需要推出自己的VirtualizingStackPanel或ItemContainerGenerator以跟蹤組中顯示的容器。這聽起來很荒謬,但WPF中默認的分組虛擬化至少沒有說。

+0

這就是我的想法,但是我希望我不會因爲寫入虛擬化面板而變得棘手。 ...因爲它作爲一個整體是項目,所以當ItemContainerGenerator'通過'SelectedItem'時總是返回'null'? – Dennis

+1

我相信是的。你應該看看Bea Stollnitz博客。她在分組和虛擬化方面有很多好帖子:http://www.beacosta.com/ – sellmeadog

+0

謝謝。我已經閱讀了幾篇關於WPF和CollectionViewSource和分組的Bea Stollnitz帖子 - 我在我的問題中實際使用了她的分組示例。 – Dennis

相關問題