簡體   English   中英

將 ListBox 放入 ScrollViewer:鼠標滾輪不起作用

[英]Putting ListBox in ScrollViewer: mouse wheel does not work

ListBox放入ScrollViewer時,我的鼠標滾輪不起作用。

ListBox是否以某種方式“竊取”了這個事件?

<ScrollViewer VerticalScrollBarVisibility="Auto" Style="{StaticResource myStyle}">
<ListBox>
  <ListBoxItem>Test 1</ListBoxItem>
  <ListBoxItem>Test 2</ListBoxItem>
  <ListBoxItem>Test 3</ListBoxItem>
  <ListBoxItem>Test 4</ListBoxItem>
  <ListBoxItem>Test 5</ListBoxItem>
  <ListBoxItem>Test 6</ListBoxItem>
  <ListBoxItem>Test 7</ListBoxItem>
</ListBox>
</ScrollViewer>

編輯:按照 Joel 的要求,添加了我這樣做的原因。我這樣做是因為我不喜歡ListBox的內部ScrollViewer對我的布局所做的事情。 我有一個背景圖片,最上面是一個ListBox ,如下所示:

替代文本 http://robbertdam.nl/share/1.png

現在,當滾動條出現時,會發生以下情況:

替代文本 http://robbertdam.nl/share/2.png

我為ScrollViewer創建了一個 Style,它在ListBox項目的內容頂部顯示滾動條。 ListBox項的數據模板中,我為滾動條的顯示保留了一些空間。

謝謝,羅伯特大壩

首先,我認為您需要詳細說明您的局限性以及您想要實現的目標。 沒有它,我只能解釋為什么你在做什么不起作用。 有人甚至可能對如何獲得您想要的結果有更好的想法。

如果將ListBox放在ScrollViewer中,則ListBox控件模板內部仍然有自己的ScrollViewer 當鼠標光標位於ListBox上並且您滾動鼠標滾輪時,該事件會冒泡,直到到達屬於ListBoxScrollViewer為止。 那一個通過滾動來處理它並將事件標記為已處理,因此您將ListBox放入其中的ScrollViewer將忽略該事件。

如果您使ListBox比外部ScrollViewer更高更窄,並為其提供足夠的項目以便ListBox本身可以滾動項目,您將看到 2 個垂直滾動條:1 個在ListBox中,1 個在ListBox外部用於外部ScrollViewer 當鼠標光標位於ListBox內時, ListBox將使用其內部的ScrollViewer項目,並且其Border將保持原位。 當鼠標光標位於ListBox外部和外部ScrollViewer內部時, ScrollViewer將滾動其內容( ListBox ),您可以通過注意ListBoxBorder改變位置來驗證這一點。

如果您希望外部ScrollViewer滾動整個ListBox控件(包括Border而不僅僅是項目),您需要重新設置ListBox的樣式,使其沒有內部ScrollViewer ,但您還需要確保它根據其項目自動變大。

出於幾個原因,我不推薦這種方法。 如果ScrollViewer中還有其他控件以及ListBox可能有意義,但您的示例並未表明這一點。 此外,如果ListBox中有很多項目,您將為每個項目創建ListBoxItem ,從而消除默認的、非重新樣式化的ListBox由於默認的VirtualizingStackPanel給您帶來的任何優勢。

請讓我們知道您的實際要求是什么。


編輯:好的,現在我有了一個更好的主意,加上這些圖像。 您得到的效果是,當有足夠多的項目可以滾動並且出現滾動條時,可用區域必須水平縮小一點,因為ScrollViewer的模板使用了Grid 這些似乎是您的選擇,按從小到大的順序排列:

  1. 重新設置ListBox的樣式使其沒有ScrollViewer並在ListBox外部使用重新設置樣式的ScrollViewer 然后您還必須強制ListBox也足夠高以顯示相同Style中的每個項目,現在您已經失去了 UI 虛擬化。 如果您要在列表中顯示數百個項目,您絕對不想丟失它。
  2. 重新設置ListBox的樣式並將ControlTemplate設置為使用具有您已為其創建的樣式的ScrollViewer ,將滾動條放在內容上方而不是單獨的列中。 這個沒問題( ListBox開始限制它的高度並使用VirtualizingStackPanel ,是的),但正如你所說,它需要在你的DataTemplate中意識到這一點。
  3. 重新設置ScrollViewer的樣式,為垂直滾動條留出空間,即使它不可見。 這是此選項的外觀:

默認情況下, ScrollViewerGrid中使用 2 列,等效於:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

因此,當滾動條從Width="Auto"開始不可見時,滾動條列的Width為 0。 為了在隱藏時為滾動條留出空間,我們將該列的Width綁定到垂直滾動條的Width

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="*" />
    <ColumnDefinition
        Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" />
</Grid.ColumnDefinitions>

所以現在ScrollViewer的自定義Style中的ControlTemplate可能如下所示:

<ControlTemplate
    TargetType="{x:Type ScrollViewer}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition
                Width="{Binding ElementName=PART_VerticalScrollBar, Path=Width}" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition
                Height="Auto" />
        </Grid.RowDefinitions>

        <ScrollContentPresenter />

        <ScrollBar
            Grid.Column="1"
            Name="PART_VerticalScrollBar"
            Value="{TemplateBinding VerticalOffset}"
            Maximum="{TemplateBinding ScrollableHeight}"
            ViewportSize="{TemplateBinding ViewportHeight}"
            Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
        <ScrollBar
            Name="PART_HorizontalScrollBar"
            Orientation="Horizontal"
            Grid.Row="1"
            Value="{TemplateBinding HorizontalOffset}"
            Maximum="{TemplateBinding ScrollableWidth}"
            ViewportSize="{TemplateBinding ViewportWidth}"
            Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />

    </Grid>
</ControlTemplate>

您甚至可以將內容列設置為固定大小,將滾動條列設置為Width="*" ,如果您的圖像未拉伸,從長遠來看,這可能會更好。 現在DataTemplate不必補償滾動條的寬度,因為無論滾動條是否可見,它都可以使用一致的區域。

您可能想要查看ScrollViewer的示例ControlTemplate的其余部分,但這些示例不是默認樣式。 請注意,該示例將垂直滾動條放在左側! 另請注意底部關於ContentScrollPresenter的評論。

我正在處理同樣的問題。 我設置了ListBox.ItemsPanel屬性,沒有任何ScrollViewer

 <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
     <ListBox>
          <ListBox.Template>
             <ControlTemplate TargetType="ItemsControl">
                 <Border>
                     <ItemsPresenter />
                 </Border>
             </ControlTemplate>
          </ListBox.Template>
          <ListBox.ItemsPanel>
              <ItemsPanelTemplate>
                  <VirtualizingStackPanel />
              </ItemsPanelTemplate>
          </ListBox.ItemsPanel>
    <\ListBox>
<\ScrollViewer>

希望這可以幫助。

請參閱此鏈接以獲得另一個答案: 當鼠標懸停在 ListBox 上時在 ScrollViewer 中滾動

您好,我認為您可以處理整個 ListBox 的 PreviewMouseWheel 事件。 只要您不處理每個項目的,這也會影響單個項目

PreviewMouseWheel and mark the event as handled:
    private void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (e.Delta < 0)
        {
            scrollViewer1.LineDown();
        }
        else
        {
            scrollViewer1.LineUp();
        }
    }

如果您只想使鼠標滾動工作並且不需要 ScrollViewer 的樣式:

  • 刪除外部 ScrollViewer。
  • 使用 ListBox 內部的 ScrollViewer 的附加屬性。

請參閱此示例的前兩行:

<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto" 
         ScrollViewer.HorizontalScrollBarVisibility="Auto">
  <ListBoxItem>Test 1</ListBoxItem>
  <ListBoxItem>Test 2</ListBoxItem>
  <ListBoxItem>Test 3</ListBoxItem>
  <ListBoxItem>Test 4</ListBoxItem>
  <ListBoxItem>Test 5</ListBoxItem>
  <ListBoxItem>Test 6</ListBoxItem>
  <ListBoxItem>Test 7</ListBoxItem>
</ListBox>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM