2011-07-23 36 views
3

我有一個列表框,在一個網格內的擴展器。 ListBox綁定到IList。擴展器,網格和列表框=沒有虛擬化

當我第一次展開Expander控件時,ListBox將處理IList中的所有項目(可以是數千個),而不是僅處理屏幕上可見的項目。

但是,如果我修復了ListBox控件的高度,它的行爲與預期相同,只能訪問IList中可見的那些項目。

實際上,虛擬化不起作用,儘管我認爲這與ListBox無法在內容項準備時確定高度有關。

的XAML基本如下(一些東西,爲了簡化刪除)...

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*" /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <Expander ExpandDirection="Right" 
       Grid.Column="0" 
       Grid.Row="0" 
       Grid.RowSpan="2" 
       Header="Documents" 
       IsExpanded="False"> 
     <Grid> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="auto" /> 
       <RowDefinition Height="*" /> 
      </Grid.RowDefinitions> 
      <Grid Grid.Row="0"> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="50" /> 
       </Grid.RowDefinitions> 
      </Grid> 
      <ListBox Name="listBox" 
        Grid.Row="1" 
        ItemsSource="{Binding Path=Items}" 
        SelectedIndex="{Binding Path=SelectedIndex}" 
        SelectedItem="{Binding Path=SelectedItem}" 
        SelectionMode="Single" 
        Width="250"> 
       <ListBox.ItemTemplate> 
        <DataTemplate> 
         <Grid> 
          <Grid.ColumnDefinitions> 
           <ColumnDefinition Width="*" /> 
           <ColumnDefinition Width="*" /> 
          </Grid.ColumnDefinitions> 
          <Grid.RowDefinitions> 
           <RowDefinition Height="auto" /> 
          </Grid.RowDefinitions> 
          <TextBlock Grid.Column="0" 
             Style="{StaticResource prompt}"> 
           <TextBlock.Text> 
            <MultiBinding StringFormat="{}{0}{1:00000}"> 
             <Binding Path="..." 
               FallbackValue="0" /> 
             <Binding Path="..." /> 
            </MultiBinding> 
           </TextBlock.Text></TextBlock> 
          <TextBlock Grid.Column="1" 
             Style="{StaticResource prompt}"> 
           <TextBlock.Text> 
            <Binding Path="ItemCount" 
              StringFormat="{}{0} Items" 
              FallbackValue="" /> 
           </TextBlock.Text></TextBlock> 
         </Grid> 
        </DataTemplate> 
       </ListBox.ItemTemplate> 
      </ListBox> 
     </Grid> 
    </Expander> 
    <v:DocumentView x:Name="documentView" 
        Grid.Column="1" 
        Grid.Row="0" 
        DocumentID="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:BatchView}}, Path=ViewModel.SelectedItem.ID}" 
        IsActive="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:BatchView}}, Path=IsActive}" /> 
    <StackPanel Grid.Column="1" 
       Grid.Row="1" 
       Style="{StaticResource buttonStackStyle}"> 
     <Button Command="{Binding Path=PreviousCommand}" 
       Style="{StaticResource previousButtonStyle}" /> 
     <Button Command="{Binding Path=NextCommand}" 
       Style="{StaticResource nextButtonStyle}" /> 
    </StackPanel> 
</Grid> 

任何人都可以建議我怎麼可能會在列表框的高度設置爲Grid.Row父的的ActualHeight?或者,任何人都可以提供更好的解決方案嗎?

謝謝。

回答

1

簡短版本:刪除Grid.RowSpan從擴展器。

龍版本:

背景:(在真正的粗線條)

當你定義的RowDefinition三件事情可能發生的高度,這取決於你到底是什麼類型的單位達使用:

  1. 像素 - 放置在該行中的任何UIElement將將已定義的行高傳遞給MeasureArrange元素的方法。
  2. 自動 - 網格將通過無限高度爲Measure,然後element.DesiredSize.HeightArrange
  3. 星 - 網格將考慮像素和自動單位的所有行的高度;計算從其可用高度剩下的高度,並將其除以爲所有行定義的「恆星總數」 - 這是一顆恆星的高度;然後,根據其星形定義的乘數分配每個行高;這個高度傳遞給MeasureArrange方法。

相同的邏輯適用於僅限於寬度而不是高度的列定義。因此,明星定義是「停止」元素,像素定義也是「停止」,但它可以在渲染視圖之外,自動定義是「讓」元素成爲它想要的大小。

所有這些邏輯都是遞歸的,所以你需要考慮兩個方向(下面的解釋)。

在你的情況

在一個方向。ListBox位於星號行,因此它將被停止。父網格也停止(因爲擴展器的模板使用DockPanel也是「停止面板」)。擴展器被定義爲以星號行開始,但它跨越自動行 - 這意味着它將被允許在高度上增長直到無限遠。糟糕...時間扭轉。

現在是相反的方向。擴展器不停止,子網格不停止(因爲網格假定它具有無限高度可用),因此列表框不會停止,列表框的模板中的ScrollViewer不會停止,因此它的ViewportHeight是無限的,用於排列項目(並且是滾動查看器的子項)的VirtualizingStackPanel這意味着所有項目都在視圖中==呈現所有元素。

對於具有默認模板的WPF窗口,可以始終假定該窗口正在停止其子元素。因此,如果刪除行跨度定義尚未解決問題,請繼續遍歷,直到找到另一個未停止其子高度並更改其定義或更改面板以停止高度從增長到無窮大的元素(滾動查看器是臭名昭着的創建這些行爲,尤其是那些隱藏在模板中的行爲)。