开发者

WPF add header to ListBox so it scrolls like DataGrid

开发者 https://www.devze.com 2023-04-10 21:42 出处:网络
I\'m trying to create a layout that uses a ListBox and my custom header that looks like a ruler, but for dates (with explicit start and end dates).The goal is to have an appearance and feel similar to

I'm trying to create a layout that uses a ListBox and my custom header that looks like a ruler, but for dates (with explicit start and end dates). The goal is to have an appearance and feel similar to a DataGrid, except that the column header row would be replaced by my DateTape object. When the user scrolls horizontally, the DateTape and ListBox both scroll, but when the user scrolls vertically, only the ListBox scrolls and the DateTape stays at the top (like the column header row in the DataGrid).

So far, the best I've been able to do is as follows:

    <Window x:Class="ProjectNS.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:ProjectNS"
            Title="MainWindow" Height="350" Width="600">
        <Window.Resources>
            <DataTemplate x:Key="itemTemplate">
                <my:CustomRectangle HorizontalAlignment="Left" VerticalAlignment="Top" />
            </DataTemplate>
        </Window.Resources>
开发者_运维技巧        <DockPanel>
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="File" />
            </Menu>
            <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
                <DockPanel>
                    <my:DateTape DockPanel.Dock="Top" VerticalAlignment="Top">
                        <my:DateTape.Dates>
                            <CalendarDateRange Start="10/4/2011" End="11/4/2011" />
                        </my:DateTape.Dates>
                    </my:DateTape>
                    <ListBox ItemTemplate="{StaticResource itemTemplate}" />
                </DockPanel>
            </ScrollViewer>
        </DockPanel>
    </Window>

The only problem I have with this solution is that the vertical scrollbar for the ListBox is at the extreme right of the control which means the user has to scroll horizontally to make the scrollbar appear. I need the scrollbar visible at all times.

I tried placing the DateTape and ListBox into a ScrollViewer, but then the DateTape scrolls out of view when scrolling vertically.

FYI - My CustomRectangle object is a UserControl that allows the user to adjust the horizontal position and width real-time to position it as desired in line with the DateTape.


I ended up having to restructure a bit. The ListBox is now an ItemsControl nested within a ScrollViewer with the vertical scroll bar hidden (not disabled). I also have an independent ScrollBar docked to the right side that is tied to the vertical scroll bar in the ScrollViewer in the code-behind. This handles the vertical scrolling. Finally, a secondary ScrollViewer contains the DateTape and the ItemsControl set to handle the horizontal scrolling.

XAML

    <DockPanel x:Name="dockPanel">
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="File" />
        </Menu>
        <ScrollBar x:Name="verticalScrollBar"
                   DockPanel.Dock="Right"
                   SmallChange="1"
                   LargeChange="3"
                   Scroll="verticalScrollBar_Scroll"
                   SizeChanged="verticalScrollBar_SizeChanged"
                   Style="{StaticResource scrollBarHiderStyle}"
                   Maximum="{Binding ElementName=listScroller, Path=ScrollableHeight}" />
        <ScrollViewer x:Name="dateScroller"
                      VerticalScrollBarVisibility="Disabled"
                      HorizontalScrollBarVisibility="Auto"
                      DockPanel.Dock="Top">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <my:DateTape x:Name="dateTape"
                             DockPanel.Dock="Top"
                             VerticalAlignment="Top"
                             Dates="{Binding Source={StaticResource dateRange}}" />
                <ScrollViewer x:Name="listScroller" VerticalScrollBarVisibility="Hidden" Grid.Row="1" Foreground="{x:Null}" Panel.ZIndex="1">
                    <ItemsControl x:Name="itemsList"
                                  ItemTemplate="{StaticResource itemTemplate}"/>
                </ScrollViewer>
            </Grid>
        </ScrollViewer>
    </DockPanel>

C#

        // this function merely sets the scroll bar thumb size
        private void verticalScrollBar_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            verticalScrollBar.Track.ViewportSize = itemsList.ActualHeight / 2;
        }

        // this function links the scroll bar to the scrollviewer
        private void verticalScrollBar_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
        {
            listScroller.ScrollToVerticalOffset(e.NewValue);
        }

I tried to tie the independent ScrollBar to the scroll bar in the ItemsControl through use of a ItemsPanelTemplate, but I couldn't get that to work.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号