WPF 根据窗口大小定位元素



我目前正在开发一个应用程序,用于从SQL数据库中检索数据并将其呈现在UI中。我顺利地获得了整个功能运行,但现在我被困在 der GUI 部分。我希望 UI 适应窗口大小。元素(img、标签、文本框)具有最小高度和最小宽度,但也可以增长到最大可用空间。如果窗口太小,我希望 UI 像响应式网站一样进行调整。

最大化的窗口如下所示: 最大化窗口

窗口宽度变小,元素相应地调整: 窗口较小

我最好的方法是:

<Grid DataContext="{Binding CurrentPerson}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Person.Photo}"/>
</Grid>
<Viewbox Grid.Column="1" StretchDirection="Both" Stretch="Uniform" HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" VerticalAlignment="Center">Title:</Label>
<Label Grid.Column="0" Grid.Row="1" VerticalAlignment="Center">Name:</Label>
<Label Grid.Column="0" Grid.Row="2" VerticalAlignment="Center">Street:</Label>
<Label Grid.Column="0" Grid.Row="3" VerticalAlignment="Center">City:</Label>
<Label Grid.Column="0" Grid.Row="4" VerticalAlignment="Center">Number:</Label>
<TextBox Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="80"Text="{Binding Person.Title}"/>
<TextBox Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="300">
<TextBox.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="Person.LastName"/>
<Binding Path="Person.FirstName"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
<TextBox Grid.Column="1" Grid.Row="2" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="300" Text="{Binding Person.Street}"/>
<TextBox Grid.Column="1" Grid.Row="3" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="300" Text="{Binding Person.City}"/>
<TextBox Grid.Column="1" Grid.Row="4" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="30" Text="{Binding Person.Number}"/>
</Grid>
</Viewbox>
</Grid>

此解决方案的问题在于,当窗口变得太小时,内容会缩小以适应窗口,并且不再可读。如果图像可以移动到人员数据上方,它将节省大量空间,并且人员数据可以读取。

我玩了一下包装面板、视框、网格、制服网格等,但我无法让它按照我想要的方式工作。

任何帮助都非常感谢。

提前感谢!

这将涉及某种 C# 代码。您可以编写触发器来更改控件上的Grid.RowGrid.Column值,并使用值转换器来决定何时,但这更简单。

首先,将主网格分解为两个单独的网格。基本上,您有两个窗格,因此请在单独的网格中获取它们的内容。

<StackPanel x:Name="MainLayout" Orientation="Horizontal">
<Grid>
<!-- img -->
</Grid>
<Grid>
<Viewbox Stretch="Uniform">
<!-- Title, name, etc. -->
</Viewbox>
</Grid>
</StackPanel>

为窗口提供一个SizeChanged处理程序:

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (ActualWidth < 400)
{
MainLayout.Orientation = Orientation.Vertical;
}
else
{
MainLayout.Orientation = Orientation.Horizontal;
}
}

更新

如果您愿意,也可以使用UniformGrid来完成。

<UniformGrid x:Name="MainLayout" Columns="2">
<Grid
HorizontalAlignment="Left"
VerticalAlignment="Top"
>
<!-- img -->
</Grid>
<Viewbox 
Stretch="Uniform"
HorizontalAlignment="Left"
>
<!-- Title, name, etc. -->
</Viewbox>
</UniformGrid>

代码隐藏

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (ActualWidth < 400)
{
//MainLayout.Orientation = Orientation.Vertical;
MainLayout.Columns = 1;
}
else
{
//MainLayout.Orientation = Orientation.Horizontal;
MainLayout.Columns = 2;
}
}

更新 2

您还可以在右侧窗格中切换网格列和行:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid
HorizontalAlignment="Left"
VerticalAlignment="Top"
>
<!-- Img -->
</Grid>
<Viewbox 
x:Name="RightPane"
Grid.Column="1"
Grid.Row="0"
Stretch="Uniform" 
HorizontalAlignment="Left">
<StackPanel 
Orientation="Vertical" 
>
<!-- Title, name, etc. -->
</StackPanel>
</Viewbox>
</Grid>

代码隐藏:

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (ActualWidth < 400)
{
//MainLayout.Orientation = Orientation.Vertical;
//MainLayout.Columns = 1;
Grid.SetColumn(RightPane, 0);
Grid.SetRow(RightPane, 1);
}
else
{
//MainLayout.Orientation = Orientation.Horizontal;
//MainLayout.Columns = 2;
Grid.SetColumn(RightPane, 1);
Grid.SetRow(RightPane, 0);
}
}

我想敦促您考虑不使用Viewbox。将字体和控件缩放到窗口是不寻常的,通常不认为非常有用。但这是你的项目。

如果您确实要使用Viewbox,请阅读其Stretch属性,该属性控制它如何缩放其内容。

也看看ViewBox.StretchDirection

作为 Ed 答案的变体,您可以使用值转换器来检查图像的宽度现在是否小于要应用于它的最小尺寸。因此,您最终会得到类似于响应式网页设计中的断点概念的东西。

这篇博客文章对此进行了解释: https://www.iambacon.co.uk/blog/a-pattern-for-responsive-applications-in-wpf

如果应用程序中有许多窗口需要此功能,则此功能特别有用,以便您可以在所有窗口中重用值转换器。


在更简单的情况下,图像大小是固定的,不需要随窗口大小进行调整,您只需使用如下所示的 WrapPanel:

<WrapPanel DataContext="{Binding CurrentPerson}">
<Border BorderBrush="Black" BorderThickness="1">
<Image Grid.Row="0" Width="200" Height="200" />
</Border>
<Grid VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" VerticalAlignment="Center">Title:</Label>
<Label Grid.Column="0" Grid.Row="1" VerticalAlignment="Center">Name:</Label>
<Label Grid.Column="0" Grid.Row="2" VerticalAlignment="Center">Street:</Label>
<Label Grid.Column="0" Grid.Row="3" VerticalAlignment="Center">City:</Label>
<Label Grid.Column="0" Grid.Row="4" VerticalAlignment="Center">Number:</Label>
<TextBox Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="80" Text="{Binding Person.Title}"/>
<TextBox Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="300">
<TextBox.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="Person.LastName"/>
<Binding Path="Person.FirstName"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
<TextBox Grid.Column="1" Grid.Row="2" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="300" Text="{Binding Person.Street}"/>
<TextBox Grid.Column="1" Grid.Row="3" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="300" Text="{Binding Person.City}"/>
<TextBox Grid.Column="1" Grid.Row="4" HorizontalAlignment="Left" IsReadOnly="True" MinWidth="30" Text="{Binding Person.Number}"/>
</Grid>
</WrapPanel>

最新更新