【问题标题】:In WPF How to prevent Controls inside ScrollViewer from expanding在 WPF 中如何防止 ScrollViewer 中的控件展开
【发布时间】:2017-08-17 13:24:46
【问题描述】:

我正在尝试在 WPF 中实现一些听起来很简单的东西,但就是无法做到。 我有一个包含两个 GroupBoxes 的 ScrollViewer。第一个将其高度设置为固定值,第二个将采用窗口左侧但具有 MinHeight。每个 GroupBox 都包含一个 DataGrid。

我想做的是: 第二个组框的大小应调整为窗口左侧,其中的 DataGrid 应调整大小以填充组框,并且如果不能全部显示行,则具有它自己的滚动条。如果我将窗口大小调整为小于 GroupBox1.Height+GroupBox2.MinHeight,则窗口中应该会出现一个滚动条。

我现在得到的行为是,第二个 groupbox 的高度中的 DataGrid 随着行数的增加而增长,从而扩展了 Groupbox 并显示了 Scrollviewer 的滚动条。

我想出了一个小演示应用来展示这种行为

WPF:

<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"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow"
    Height="400"
    Width="500">
<Grid>
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="150" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <GroupBox Header="test1"
                      Grid.Row="0">
                <DataGrid ItemsSource="{Binding Colors}">
                </DataGrid>
            </GroupBox>
            <GroupBox Header="test2"
                      Grid.Row="1"
                      MinHeight="50">
                <DataGrid ItemsSource="{Binding Colors}">
                </DataGrid>
            </GroupBox>
        </Grid>

    </ScrollViewer>
</Grid>

C#

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            Colors = new List<Color>();
            for (int i = 1; i < 51; i++)
            {
                byte b = (byte)(i * 5);
                Colors.Add(Color.FromRgb(b,b,b));
            }
        }

        private List<Color> _colors;
        public List<Color> Colors
        {
            get
            {
                return _colors;
            }
            set
            {
                _colors = value;
            }
        }
    }
}

我得到了什么:

我想要什么(抱歉照片处理技巧不好):

除非如前所述,我将窗口的大小调整为小于 group1 的固定大小和 group2 的最小大小之和,在这种情况下我想要窗口的滚动条。

在这种情况下,我希望它看起来像这样:(又是一个模型,而不是实际的屏幕截图)

请注意,该示例非常简单,但我尝试在其中执行此操作的窗口要复杂得多,与此示例相比,使用垂直滚动条更有意义。

谢谢!

【问题讨论】:

  • 为 ScrollViewer 元素指定一个固定的高度?
  • @mm8 这样做会使它对可调整大小的窗口毫无用处。将 ScrollViewer 高度设置为较小的值会使其始终可见并限制组占用的空间。具有很大的价值最终会显示完全相同的问题。编辑:我试过了,只是为了确保问题存在,即使是一个小的 ScrollViewer。第二组扩展到网格的内容,我只有更少的空间可以滚动,窗口的大小调整变得无用。
  • 我不认为我理解您的问题。您的第二张图片上没有 ScrollViewer。那么你希望这个 ScrollViewer 到底什么时候出现呢?
  • 如前所述,仅当我调整窗口大小以使其太小而无法显示 Group1 的高度(固定大小)和 Group2 的 MinHeight 时,才应显示 ScrollViewer。
  • 那么你应该将ScrollViewer的Height或MinHeight设置为Group1.Height + Group2.Height。

标签: c# wpf datagrid scrollviewer


【解决方案1】:

您可以简单地将第二个GroupBoxMaxHeight 属性绑定到ScrollViewer 的容器的ActualHeight 减去第一个GroupBox

完整示例(不包括后面的代码和你的一样):

<Window.Resources>
    <wpfApp1:SubtractConverter x:Key="SubtractConverter"/>
</Window.Resources>

<Grid Name="Root">
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="150" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <GroupBox
                Name="Test1"
                Header="test1"
                Grid.Row="0">

                <DataGrid ItemsSource="{Binding Colors}"/>
            </GroupBox>
            <GroupBox
                Header="test2"
                Grid.Row="1"
                MinHeight="250">
                <DataGrid ItemsSource="{Binding Colors}"/>

                <GroupBox.MaxHeight>
                    <MultiBinding Converter="{StaticResource SubtractConverter}">
                        <Binding Path="ActualHeight" ElementName="Root"/>
                        <Binding Path="ActualHeight" ElementName="Test1"/>
                    </MultiBinding>
                </GroupBox.MaxHeight>
            </GroupBox>
        </Grid>
    </ScrollViewer>
</Grid>

public class SubtractConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double[] doubles = values.Cast<double>().ToArray();

        double result = doubles[0];

        for (int i = 1; i < doubles.Length; i++)
        {
            result -= doubles[i];
        }

        return result;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

【讨论】:

  • 正是我正在寻找的行为!非常感谢!它比我预期的要复杂,但一切都很好。只要它工作正常:)
【解决方案2】:

我不知道这是否是解决您问题的最简单方法,但您可以按照以下方式做一些事情:

<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"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="400"
Width="500">
<Window.Resources>
    <local:HeightConverter x:Key="HeightConverter"/>
</Window.Resources>
<Grid>
    <ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="MainView">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="150" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <GroupBox Header="test1"
                  Grid.Row="0">
                <DataGrid ItemsSource="{Binding Colors}">
                </DataGrid>
            </GroupBox>
            <GroupBox Header="test2"
                  Grid.Row="1"
                  x:Name="grpBox2"
                  MinHeight="50">
                <GroupBox.Height>
                    <MultiBinding Converter="{StaticResource HeightConverter}" ConverterParameter="150">
                        <Binding Path="ActualHeight" ElementName="MainView" />
                        <Binding Path="MinHeight" ElementName="grpBox2" />
                    </MultiBinding>
                </GroupBox.Height>
                <DataGrid ItemsSource="{Binding Colors}">
                </DataGrid>
            </GroupBox>
        </Grid>

    </ScrollViewer>
</Grid>

对于转换器来说是这样的:

public class HeightConverter : IMultiValueConverter
{
   public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
   {
        if (values == null || parameter == null || values[0] == null || values[1] == null)
        {
            return null;
        }

        var currentWindowHeight = double.Parse(values[0].ToString());
        var currentMinHeight = double.Parse(values[1].ToString());

        var currentTopWindowHeight = double.Parse(parameter.ToString());

        var newHeight = currentWindowHeight - currentTopWindowHeight;

        if (newHeight < currentMinHeight)
            newHeight = currentMinHeight;

        return newHeight;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

【讨论】:

  • 太棒了!经过测试和工作,除了它不尊重 MinHeight 而优素福的解决方案。仍然非常感谢,您的两个解决方案都相似,我将在我的实际应用程序中使用受它们启发的东西。非常感谢:)
  • 嘿,不客气。奇怪的是它不尊重 MinHeight 即使它专门检查它。但无论如何很高兴我能帮上忙!干杯
猜你喜欢
  • 1970-01-01
  • 2011-02-28
  • 1970-01-01
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多