在 WPF 中如何防止 ScrollViewer 中的控件展开
In WPF How to prevent Controls inside ScrollViewer from expanding
我正在尝试在 WPF 中实现一些听起来很简单,但无法解决的问题。
我有一个包含两个 GroupBox 的 ScrollViewer。第一个将其高度设置为固定值,第二个将采用 window 的剩余部分但具有 MinHeight。每个 GroupBox 包含一个 DataGrid。
我想做的是:
第二个组框的大小应调整为 Window 的左侧,其中的 DataGrid 的大小应调整为填充组框,如果行不能全部显示,则应有自己的滚动条。如果我将 window 的大小调整为小于 GroupBox1.Height+GroupBox2.MinHeight,则 window 中应该会出现一个滚动条。
我现在得到的行为是,第二个分组框的高度中的 DataGrid 随着行数的增加而增长,从而扩展了分组框并显示了 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;
}
}
}
}
我得到了什么:
我想要什么(抱歉照片处理技巧不好):
除非,如前所述,我将 window 的大小调整为小于 group1 的固定大小和 group2 的最小大小之和,在这种情况下,我需要 window 的滚动条。
在这种情况下,我希望它看起来像这样:(再次是模型,而不是实际的屏幕截图)
请注意,该示例非常简单,但我尝试在其中执行的 window 复杂得多,并且使用垂直滚动条比在本示例中更有意义。
谢谢!
我不知道这是否是解决您问题的最简单方法,但您可以按照以下方法做一些事情:
<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();
}
}
您可以简单地将第二个 GroupBox
的 MaxHeight
属性 绑定到 ScrollViewer
减去第一个 [=] 的容器的 ActualHeight
13=].
完整示例(不包括后面跟你一样的代码):
<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();
}
}
我正在尝试在 WPF 中实现一些听起来很简单,但无法解决的问题。 我有一个包含两个 GroupBox 的 ScrollViewer。第一个将其高度设置为固定值,第二个将采用 window 的剩余部分但具有 MinHeight。每个 GroupBox 包含一个 DataGrid。
我想做的是: 第二个组框的大小应调整为 Window 的左侧,其中的 DataGrid 的大小应调整为填充组框,如果行不能全部显示,则应有自己的滚动条。如果我将 window 的大小调整为小于 GroupBox1.Height+GroupBox2.MinHeight,则 window 中应该会出现一个滚动条。
我现在得到的行为是,第二个分组框的高度中的 DataGrid 随着行数的增加而增长,从而扩展了分组框并显示了 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;
}
}
}
}
我得到了什么:
我想要什么(抱歉照片处理技巧不好):
除非,如前所述,我将 window 的大小调整为小于 group1 的固定大小和 group2 的最小大小之和,在这种情况下,我需要 window 的滚动条。
在这种情况下,我希望它看起来像这样:(再次是模型,而不是实际的屏幕截图)
请注意,该示例非常简单,但我尝试在其中执行的 window 复杂得多,并且使用垂直滚动条比在本示例中更有意义。
谢谢!
我不知道这是否是解决您问题的最简单方法,但您可以按照以下方法做一些事情:
<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();
}
}
您可以简单地将第二个 GroupBox
的 MaxHeight
属性 绑定到 ScrollViewer
减去第一个 [=] 的容器的 ActualHeight
13=].
完整示例(不包括后面跟你一样的代码):
<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();
}
}