WPF 根据窗口大小定位元素

beg*_*ego 3 c# wpf layout xaml screen-resolution

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

最大化的窗口会像这样: Maximized window

窗口宽度变小并且元素相应调整: 较小的窗口

我最好的方法是:

<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>
Run Code Online (Sandbox Code Playgroud)

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

我尝试过wrappanel、viewbox、grid、uniformgrid 等,但我无法让它按照我想要的方式工作。

很感谢任何形式的帮助。

提前致谢!

15e*_*153 5

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

首先,将主网格分解为两个独立的网格。基本上,这里有两个窗格,因此将它们的内容放在单独的网格中。

<StackPanel x:Name="MainLayout" Orientation="Horizontal">
    <Grid>
        <!-- img -->
    </Grid>

    <Grid>
        <Viewbox Stretch="Uniform">
            <!-- Title, name, etc. -->
        </Viewbox>
    </Grid>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

给窗口一个SizeChanged处理程序:

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

更新

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

<UniformGrid x:Name="MainLayout" Columns="2">
    <Grid
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        >
        <!-- img -->
    </Grid>

    <Viewbox 
        Stretch="Uniform"
        HorizontalAlignment="Left"
        >
        <!-- Title, name, etc. -->
    </Viewbox>
</UniformGrid>
Run Code Online (Sandbox Code Playgroud)

代码隐藏

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新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>
Run Code Online (Sandbox Code Playgroud)

背后代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

ViewBox.StretchDirection也看看吧。