如何使用 WPF XAML 构建堆叠表单?

问题描述 投票:0回答:4

在我的窗户上,我有一个

GroupBox
。我想在其中构建一个水平对齐的表格
GroupBox
。水平对齐是指标签和输入位于同一网格行或 x 轴上的表单。单独的表单标签+输入位于各自的行中。

由于

GroupBox
只能有一个子内容,我认为我需要使用
Grid
StackPanel
。我正在尝试使用
StackPanel
,因为这看起来更简单,并且应该实现我的目标。

我试图解决的问题是如何将输入和标签分组为一个单元,以便它们可以水平彼此相邻,但在

StackPanel
内垂直堆叠为一对。

c# wpf xaml
4个回答
1
投票

最好使用

Grid
,这样你就可以让标签和输入垂直排列。虽然使用堆栈面板并非不可能,但要困难得多。如果将网格的
RowDefinition
高度设置为“自动”,网格将仅达到所需的高度:

<GroupBox>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Text="Label1"/>
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Input1}"/>
        <TextBlock Grid.Row="1" Grid.Column="0" Text="Label2"/>
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Input2}"/>
        etc.
    </Grid>
</GroupBox>

您可能需要使用边距和/或填充和水平对齐来使布局完全符合您的要求,但这应该为您提供实现您想要的效果所需的控制。


1
投票

您可以在组框内使用方向等于垂直的堆栈面板,并在该堆栈面板内使用另一个方向等于水平的堆栈面板,用于标签和输入,就像下面的示例代码一样。

<GroupBox Header="Sample GroupBox">
  <StackPanel Orientation="Vertical">
    <StackPanel Name="input1" Orientation="Horizontal">
      <Label Content="input1"/>
      <TextBox/>
    </StackPanel>
    <StackPanel Name="input2" Orientation="Horizontal">
      <Label Content="input2"/>
      <TextBox/>
    </StackPanel>
    <StackPanel Name="input3" Orientation="Horizontal">
      <Label Content="input3"/>
      <TextBox/>
    </StackPanel>
  </StackPanel>
</GroupBox>


1
投票

您可能会发现有用的一个功能是网格共享大小范围。它可以帮助您通过共享列来对齐多个不同网格中的元素 ow 尺寸,像这样:

<GroupBox Header="Sample GroupBox">
    <StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"  SharedSizeGroup="firstGroup" />
                <ColumnDefinition Width="Auto"  SharedSizeGroup="secondGroup" />
            </Grid.ColumnDefinitions>
            <Label Content="input11" Grid.Column="0" />
            <TextBox Grid.Column="1" Width="100"/>
        </Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"  SharedSizeGroup="firstGroup" />
                <ColumnDefinition Width="Auto"  SharedSizeGroup="secondGroup" />
            </Grid.ColumnDefinitions>
            <Label Content="input2222222" Grid.Column="0" />
            <TextBox Grid.Column="1"/>
        </Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"  SharedSizeGroup="firstGroup" />
                <ColumnDefinition Width="Auto"  SharedSizeGroup="secondGroup" />
            </Grid.ColumnDefinitions>
            <Label Content="input3333333333333" Grid.Column="0" />
            <TextBox Grid.Column="1"/>
        </Grid>
    </StackPanel>
</GroupBox>

我并不是说上面的代码中有必要,但这只是示例。通常,您希望在 ItemsControl 的 ItemTemplate 等中使用网格,并且希望所有项目对齐。这里共享大小范围可能会有所帮助。


0
投票

这里是一个轻量级的表单布局解决方案,不需要第三方库和很多布局属性代码:

预览:

(仅限核心代码:)
C# 代码:

using System.Windows;
using System.Windows.Controls;

namespace Flithor_Codes
{
    public class TemplatedItemsControl : ItemsControl
    {
        // force apply ItemTemplate for each control element
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return false;
        }
        // apply ItemTemplate for each generated container
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            ((ContentPresenter)element).ContentTemplate = ItemTemplate;
        }
    }
    // For define the field name
    public static class SimpleField
    {
        public static readonly DependencyProperty FieldNameProperty = DependencyProperty.RegisterAttached(
            "FieldName", typeof(string), typeof(SimpleField), new PropertyMetadata(default(string)));

        public static void SetFieldName(DependencyObject element, string value)
        {
            element.SetValue(FieldNameProperty, value);
        }

        public static string GetFieldName(DependencyObject element)
        {
            return (string)element.GetValue(FieldNameProperty);
        }
    }
}

在 XAML 中使用:

<!-- Set this control is Shared Size Scope make ColumnDefinition.SharedSizeGroup works -->
<fc:TemplatedItemsControl Grid.IsSharedSizeScope="True">
    <fc:TemplatedItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type FrameworkElement}">
            <Grid Margin="0,0,0,3">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"
                                      MinWidth="80"
                                      SharedSizeGroup="FieldName" />
                    <ColumnDefinition Width="8" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <TextBlock HorizontalAlignment="Right"
                           VerticalAlignment="Center"
                           Text="{Binding Path=(fc:SimpleField.FieldName)}" />
                <ContentPresenter Grid.Column="2" Content="{Binding}" />
            </Grid>
        </DataTemplate>
    </fc:TemplatedItemsControl.ItemTemplate>
    <!-- simple fields editor definition -->
    <TextBox x:Name="txt_Name"
             fc:SimpleField.FieldName="Name"
             Text="{Binding Name}" />
    <ComboBox x:Name="txt_Sex"
              fc:SimpleField.FieldName="Sex"
              ItemsSource="{x:Static my:Constains.SexList}"
              SelectedItem="{Binding Sex}" />
    <TextBox x:Name="txt_Age"
             fc:SimpleField.FieldName="Age"
             Text="{Binding Age}" />
    <ComboBox x:Name="txt_Job"
              fc:SimpleField.FieldName="Job"
              IsEditable="True"
              ItemsSource="{x:Static my:Constains.JobList}"
              Text="{Binding Job}" />
</fc:TemplatedItemsControl>
© www.soinside.com 2019 - 2024. All rights reserved.