如何在不超过窗口高度的情况下使WPF网格行具有自动高度? [英] How do I have a WPF Grid row be of Auto height without exceeding the window height?

查看:55
本文介绍了如何在不超过窗口高度的情况下使WPF网格行具有自动高度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包含ItemsControl的窗口,该窗口中可以包含可变数量的控件.为了解决窗口高度超出容纳的情况,我将其包裹在ScrollViewer中,以便在项数超出可用高度时显示滚动条.

I have a window that contains a ItemsControl that can have a variable number of controls inside. In order to account for the case where there are more than will fit in the window height, I wrapped it in a ScrollViewer, so that a scrollbar would be shown when the number of items was more than would fit in the height available.

现在,问题在于,ItemsControl中有时没有任何显示,有时甚至没有.因此,我将网格行的高度设置为Auto,以允许ItemsControl在为空时消失,或在需要时增大.但是,这意味着即使行超过了窗口的高度,该行也可以根据需要获取高度,并且永远不会显示垂直滚动条.

Now, the problem is that sometimes there won't be anything to show in the ItemsControl and sometimes there will. Therefore, I set the grid row's height to Auto to allow the ItemsControl to disappear when empty, or grow when needed. However, this means that the row takes as much height as it needs, even if this exceeds the window height, and the vertical scrollbar is never shown.

以下是用于示例窗口的XAML,用于演示问题...

Here is some XAML for a sample window that demonstrates the issue...

<Window x:Class="DuplicateCustomerCheck.TestScrollViewerWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Test Scroll Viewer Window"
        Height="450"
        Width="200">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <TextBox Name="N"
             TextChanged="TextBoxBase_OnTextChanged"
             Grid.Row="0"
             Margin="3" />

    <Grid Margin="3"
          Grid.Row="1">
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <TextBlock Text="Possible duplicate of..."
                 Margin="3" />
      <ScrollViewer VerticalScrollBarVisibility="Visible"
                    Grid.Row="1">

        <ItemsControl Name="MatchingNames"
                      ItemsSource="{Binding MatchingNames, Mode=TwoWay}">
          <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
              <StackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>

          <ItemsControl.ItemTemplate>
            <DataTemplate>
              <Button Content="{Binding Item}" />
            </DataTemplate>
          </ItemsControl.ItemTemplate>
        </ItemsControl>
      </ScrollViewer>
    </Grid>

    <TextBlock Grid.Row="2"
               Margin="3"
               Text="Stuff at the bottom" />
  </Grid>
</Window>

出于演示目的,这里是按钮的事件处理程序,它使我可以测试不同数量的项目(请注意,这是点头代码,因此没有错误检查等)...

For demonstration purposes, here is the button's event handler that allows me to test different numbers of items (note that this is noddy code, so no error-checking etc)...

private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e) {
  MatchingNames.ItemsSource = Enumerable
    .Range(0, int.Parse(N.Text))
    .Select(n1 => new {
      Item = "Button " + n1
    });
}

如果我将第二个网格行的高度更改为*,那么它可以正常工作,但这意味着ItemsControl是永久可见的,这是我不想要的.仅当其中有某些项目时才显示.

If I change the second grid row's height to * then it works fine, but this means that the ItemsControl is permanently visible, which I don't want. It should only be shown when there are some items in it.

我尝试了代码),但没有任何区别.

I tried the ScrollViewerMaxSizeBehavior behaviour from this blog post (code here), but it didn't make any difference.

任何人都知道我如何允许ItemsControl占用其所需的垂直空间,包括零,但不超过窗口的高度吗?

Anyone any idea how I can allow the ItemsControl to take as much vertical space as it needs, including zero, but not grow taller than can fit in the window?

推荐答案

我在发布类似的问题之后,发现了这个问题.至少我认为我们要问的是同一件事,尽管您提到因此,我将网格行的高度设置为自动",以使ItemsControl在为空时消失,或在需要时增长."但是,当我尝试采样时,即使是空的,ScrollViewer仍会显示其滚动条,并且会占用空间.

I found this question after I had posted a similar question. At least I think we're asking the same thing, although you mention "Therefore, I set the grid row's height to Auto to allow the ItemsControl to disappear when empty, or grow when needed." However, when I tried your sample, even when empty, the ScrollViewer is still showing its scrollbars and it's taking up space.

无论如何,妈妈回答了我的问题,尽管他们的回答并不完全适合我,与马库斯的答案使我想到了

In any case, mami answered my question, and although their answer didn't exactly work for me, it along with Markus's answer led me to coming up with my own answer.

尽管我的回答与您的情况不太吻合,因为我认为ItemsControlGrid行中的唯一内容,而您在其中可能有"...的可能重复项" TextBlock排.我调整了答案以考虑TextBlock的大小,但是它并不像我希望的那样干净.作为一种可能的优化,当计算ItemsControlItem的总高度时,一旦高度变得足够大"(例如,大于Window的高度),您可能会提早退出.这样,如果您有数千个项目,而实际上只有几十个项目可以显示在屏幕上,那么您可以得到几十个项目的高度,而不是数千个项目的高度.

My answer doesn't quite work with your situation though, since mine assumes that the ItemsControl is the only thing in the Grid row, while you have the "Possible duplicate of..." TextBlock in the row too. I tweaked my answer to take the size of the TextBlock into account, but it's not as clean as I'd like it to be. As a possible optimization, when computing the total height of the ItemsControl's Items, you could probably exit early once the height gets "big enough" (e.g., larger than the Window's height). That way, if you have thousands of items and only a few dozen would realistically fit on screen, you can just get the height of the few dozen instead of the thousands.

无论如何,也许它会给你一些想法:)

In any case, perhaps it'll give you some ideas :)

XAML:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" MaxHeight="{Binding ItemMaxHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"/>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <TextBox Name="N"
             TextChanged="TextBoxBase_OnTextChanged"
             Grid.Row="0"
             Margin="3" />

        <Grid Margin="3"
          Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock Name="tb" Text="Possible duplicate of..."
                 Margin="3" />
            <ScrollViewer VerticalScrollBarVisibility="Visible"
                    Grid.Row="1">

                <ItemsControl Name="MatchingNames"
                      ItemsSource="{Binding MatchingNames, Mode=TwoWay}"
                      SizeChanged="MatchingNames_SizeChanged">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>

                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Button Content="{Binding Item}" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </ScrollViewer>
        </Grid>

        <TextBlock Grid.Row="2"
               Margin="3"
               Text="Stuff at the bottom" />
    </Grid>
</Window>

后面的代码:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        MatchingNames.ItemsSource = Enumerable
          .Range(0, int.Parse(N.Text))
          .Select(n1 => new
          {
              Item = "Button " + n1
          });
    }

    public double ItemMaxHeight
    {
        get
        {
            if (MatchingNames == null)
                return double.PositiveInfinity;

            double height = 0.0;
            var icg = MatchingNames.ItemContainerGenerator;
            for (int i = 0; i < MatchingNames.Items.Count; i++)
                height += (icg.ContainerFromIndex(i) as FrameworkElement).ActualHeight;

            return height 
                + tb.Margin.Top + tb.ActualHeight + tb.Margin.Bottom
                + 6.0; // 6 should match the margin of the scrollviewer
        }
    }

    private void MatchingNames_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (e.HeightChanged)
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ItemMaxHeight"));
    }
}

这篇关于如何在不超过窗口高度的情况下使WPF网格行具有自动高度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆