WPF:Scrollviewer 内的 ListView;布局问题

发布于 2024-10-02 09:57:12 字数 2773 浏览 0 评论 0原文

我确实有一个关于在滚动查看器内使用列表视图进行布局的问题。一旦列表视图位于滚动查看器内,它就会使用其最大尺寸,并且不会自行滚动,因为滚动查看器为其内部的控件提供无限量的空间。 问题是,只有当用户向下滚动时,长列表下方的控件才可见,并且我想让列表视图仅使用必要的空间并使用滚动条本身。图片确实比文字能传达更多信息(图片链接也能传达更多信息,因为我的声誉还不到 10。编辑2:好吧,我只能使用一个链接,所以我将所有图片复制到一个链接上)。 如果列表不长,一切都可以:

图片 1 : https://i.sstatic.net/7dDEC.jpg

现在,如果列表更长,下面的控件将向下移动到不可见的区域:

图 2:参见图 1 中的链接

我现在想要发生的是:

图 3:参见图 1 中的链接

它本身并不是真正的问题的原因是我们可以将所有内容放入停靠面板中,并将下面的控件停靠到 Dock.Below 和从上到上,并让列表视图用“lastchildfill”填充中心。现在来说说真正的问题。如果窗口变小怎么办?然后,首先列表视图消失,然后其他所有内容也消失,而没有滚动条滚动到底部的控件。

图 4:参见图 1 中的链接

我正在寻找的理想解决方案是在窗口(或根滚动查看器)上有滚动条,这将使我们能够滚动到窗口的每个部分,如下所示只要所有内容都达到最小尺寸,外部滚动条就可见。

图 5:参见图 1 中的链接

有什么想法吗?图片太多?这里有一些 xaml 供大家尝试使其工作(这只是一个快速示例窗口......)

<Window x:Class="WpfTest1.ScrollTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ScrollTestWindow" Height="400" Width="700">
    <ScrollViewer >
        <DockPanel LastChildFill="True" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Visible">
            <Grid DockPanel.Dock="Top">
                <TextBlock Text="Example controls above listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <Grid DockPanel.Dock="Bottom">
                <TextBlock Text="Example controls below listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <ListView FontSize="30">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Width="190" Header="Date" />
                        <GridViewColumn Width="200" Header="Day Of Week"  DisplayMemberBinding="{Binding DayOfWeek}" />
                        <GridViewColumn Width="120" Header="Year" DisplayMemberBinding="{Binding Year}" />
                    </GridView>
                </ListView.View>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
            </ListView>
        </DockPanel>

    </ScrollViewer>

i do have a question about layouting with a listview inside of a scrollviewer. Once a listview is inside a scrollviewer it does use it's maximum size and doesn't scroll itself cause the scrollviewer offers unlimited amount of space to the controls inside of it.
The problem is, that controls that are below a long list are only visible if the user scrolls down and I want to make the listview only use the space that is necessary and use a scrollbar itself. Pictures do tell more information than words (links for pictures also do tell much as my reputation isn't at 10 yet.. Edit2: well i can use only one link so i copied all pictures onto one).
If the lists isn't long everything is okay:

Picture 1 : https://i.sstatic.net/7dDEC.jpg

Now if the list is longer the controls below move down into the invisible land:

Picture 2 : see link from picture 1

What I do want to happen now is this:

Picture 3 : see link from picture 1

That itself isn't really a problem cause we could put everything in a dockpanal and do dock the controls below to Dock.Below and Top to Top and let the listview fill the center with "lastchildfill". Now for the real problem. What if the window gets smaller? Then at first the listview disappears and then also everything else without having a scrollbar to scroll to the controls on the bottom.

Picture 4 : see link from picture 1

The ideal solution i am searching for is to have scrollbars on the window (or a root scrollviewer) which would enable us to scroll to every section of the window like this and just have the outer scrollbars to be visible once everything is a minimum size.

Picture 5 : see link from picture 1

ANY IDEAS? too many pictures? here's a little bit of xaml for everyone to try making it work (it's just a fast example windows...)

<Window x:Class="WpfTest1.ScrollTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ScrollTestWindow" Height="400" Width="700">
    <ScrollViewer >
        <DockPanel LastChildFill="True" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Visible">
            <Grid DockPanel.Dock="Top">
                <TextBlock Text="Example controls above listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <Grid DockPanel.Dock="Bottom">
                <TextBlock Text="Example controls below listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <ListView FontSize="30">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Width="190" Header="Date" />
                        <GridViewColumn Width="200" Header="Day Of Week"  DisplayMemberBinding="{Binding DayOfWeek}" />
                        <GridViewColumn Width="120" Header="Year" DisplayMemberBinding="{Binding Year}" />
                    </GridView>
                </ListView.View>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
                <sys:DateTime>1/1/1</sys:DateTime>
            </ListView>
        </DockPanel>

    </ScrollViewer>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

就是爱搞怪 2024-10-09 09:57:12

好的。所以我也遇到了同样的问题,但现在已经解决了!

我的项目看起来和你的有点不同,但我认为它应该适合你。我提出的解决方案也有一些限制。例如,仅当您仅添加一个ListView时,它才会起作用!在您的示例中,您只有一个,因此这不会成为问题。但对于任何可能想要更多ListViews 的人来说,您必须添加更多功能来决定视图的大小以及放置它们的位置。

您还必须为 ListView 设置 MinHeight

我的解决方案是创建您自己的面板类来扩展 StackPanel,覆盖MeasureOverrideArrangeOverride 函数。并将ListView添加到创建的面板

CustomPanel:

public class ScrollablePanel : StackPanel
{
    protected override Size MeasureOverride(Size constraint)
    {
        Size tmpSize = base.MeasureOverride(constraint);
        tmpSize.Height = (double)(this.Children[0] as UIElement).GetValue(MinHeightProperty);
        return tmpSize;
    }

    protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
    {
        Size tmpSize = new Size(0, 0);

        //Width stays the same
        tmpSize.Width = finalSize.Width;
        
        //Height is changed
        tmpSize.Height = finalSize.Height;

        //This works only for one child!
        this.Children[0].SetCurrentValue(HeightProperty, tmpSize.Height);
        this.Children[0].Arrange(new Rect(new Point(0, 0), tmpSize));
        
        return tmpSize;
    }
}

XAML

<Window x:Class="WpfTest1.ScrollTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfTest1"
Title="ScrollTestWindow" Height="400" Width="700">
    <ScrollViewer >
        <DockPanel LastChildFill="True" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Visible">
            <Grid DockPanel.Dock="Top">
                <TextBlock Text="Example controls above listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <Grid DockPanel.Dock="Bottom">
                <TextBlock Text="Example controls below listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <local:ScrollablePanel>
                <ListView FontSize="30" MinHeight="80">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Width="190" Header="Date" />
                            <GridViewColumn Width="200" Header="Day Of Week"  DisplayMemberBinding="{Binding DayOfWeek}" />
                            <GridViewColumn Width="120" Header="Year" DisplayMemberBinding="{Binding Year}" />
                        </GridView>
                    </ListView.View>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                </ListView>
            </local:ScrollablePanel>
        </DockPanel>

    </ScrollViewer>
</Window>

这个问题很久以前就被问过,但我希望这个答案至少会帮助某人!

我还要感谢 @sisyphe 为解决此问题提供的所有帮助:)

Ok. So I had the same problem, but have now managed to solve it!

My project looks a little different than yours, but I think that it should work for you to. The solution that I'm presenting also has some limitation to it. For example, it will only work if you only add one ListView! In your example you only have one, so that won't be a problem there. But for anyone that might want more ListViews, you'll have to add more functionality for deciding the sizes of the Views, and where to put them.

You will also have to have a MinHeight set for the ListView.

My solution is to create you own panel class that extends a StackPanel, override the MeasureOverride and the ArrangeOverride functions. And add the ListView into the created Panel

CustomPanel:

public class ScrollablePanel : StackPanel
{
    protected override Size MeasureOverride(Size constraint)
    {
        Size tmpSize = base.MeasureOverride(constraint);
        tmpSize.Height = (double)(this.Children[0] as UIElement).GetValue(MinHeightProperty);
        return tmpSize;
    }

    protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
    {
        Size tmpSize = new Size(0, 0);

        //Width stays the same
        tmpSize.Width = finalSize.Width;
        
        //Height is changed
        tmpSize.Height = finalSize.Height;

        //This works only for one child!
        this.Children[0].SetCurrentValue(HeightProperty, tmpSize.Height);
        this.Children[0].Arrange(new Rect(new Point(0, 0), tmpSize));
        
        return tmpSize;
    }
}

The XAML

<Window x:Class="WpfTest1.ScrollTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfTest1"
Title="ScrollTestWindow" Height="400" Width="700">
    <ScrollViewer >
        <DockPanel LastChildFill="True" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Visible">
            <Grid DockPanel.Dock="Top">
                <TextBlock Text="Example controls above listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <Grid DockPanel.Dock="Bottom">
                <TextBlock Text="Example controls below listview" Background="LightGray" FontSize="30"></TextBlock>
            </Grid>
            <local:ScrollablePanel>
                <ListView FontSize="30" MinHeight="80">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Width="190" Header="Date" />
                            <GridViewColumn Width="200" Header="Day Of Week"  DisplayMemberBinding="{Binding DayOfWeek}" />
                            <GridViewColumn Width="120" Header="Year" DisplayMemberBinding="{Binding Year}" />
                        </GridView>
                    </ListView.View>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                    <sys:DateTime>1/1/1</sys:DateTime>
                </ListView>
            </local:ScrollablePanel>
        </DockPanel>

    </ScrollViewer>
</Window>

It was a long time ago this question was asked, but I hope that this answer will help at least someone!

I also like to thank @sisyphe for all the help needed to solve this problem :)

甜`诱少女 2024-10-09 09:57:12

不确定这是否真的是您理想的解决方案,但我个人的做法完全不同:

我使用一个简单的网格,其中 n 行用于列表视图上方的内容,m 行用于下面的内容,一行用于高度=的列表视图*。因此上面和下面的所有内容都是可见的,当没有足够的空间时,列表视图中会出现滚动条。

我有一个这样的工作示例,但是使用 DataGrid。它应该与 ListView 非常相似。

Not sure if this is really your ideal solution, but I personnally do this quite differently:

I use a simple grid, with n rows for what should be above the listvew, m rows for the stuff below and a row for the listview with height=*. So everything above and below is visible, a scroll bar appears in the list view when there is not enough room.

I have a working example of this, but with a DataGrid. It should be quite similar with a ListView.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文