代码之家  ›  专栏  ›  技术社区  ›  Jason Coyne

如何使用网格或其他控件在WPF中布局表单以实现可维护性

  •  13
  • Jason Coyne  · 技术社区  · 14 年前

    我有一个WPF表格,我想在上面布置一个标准表格。每个表单元素将有一个标签,然后是一个控件。相当标准的东西。

    <nobr/> ?

    有没有办法让网格使用更多HTML样式的列/行,其中的项是它们所在行的子项,以便我可以轻松地重新排序?

    9 回复  |  直到 7 年前
        1
  •  27
  •   Roet    11 年前

    有一些WPF等同于nobr吗?

    <WrapPanel Orientation="Horizontal">
       <StackPanel Orientation="Horizontal">
          <Label>Some field</Label>
          <TextBox>Some value</TextBox>
       </StackPanel>
       <StackPanel Orientation="Horizontal">
          <Label>Another field</Label>
          <TextBox>Another value</TextBox>
       </StackPanel>
       ...
    </WrapPanel>
    

    <StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True">
       <Grid>
          <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
             <ColumnDefinition Width="*"/>
          </Grid.ColumnDefinitions>
          <Label Grid.Column="0">Some field</Label>
          <TextBox Grid.Column="1">Some value</TextBox>
       </Grid>
       <Grid>
          <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
             <ColumnDefinition Width="*"/>
          </Grid.ColumnDefinitions>
          <Label Grid.Column="0">Another field</Label>
          <TextBox Grid.Column="1">Another value</TextBox>
       </Grid>
    </StackPanel>
    

    我有点讨厌XAML的冗长,尤其是你必须重复列定义。不过,如果你能正确地组织你的类并使用模板,那就没那么糟糕了。请注意,在这个方案中,您不必跟踪任何行号,因此对字段重新排序很简单。

        2
  •  6
  •   anar khalilov    6 年前

    <StackPanel Orientation="Vertical">
      <StackPanel Orientation="Horizontal">
         <Label Width="150">Name</Label>
         <TextBox Width="200" />
      </StackPanel>
      <StackPanel Orientation="Horizontal">
         <Label Width="150">Date of Birth</Label>
         <DatePicker Width="200" />
      </StackPanel>
    </StackPanel>
    

        3
  •  4
  •   Rafa Castaneda    14 年前

        4
  •  2
  •   Community Dai    4 年前

    如果你能同意的话,我推荐ExpressionBlend,如果你要做很多UI设计的话。它允许更简单地查看项目。将控件嵌套到各种容器中是使UI具有动态但结构化的好方法。

    不幸的是网格只能像你说的那样工作。其中的元素指定它们所在的行和/或列。如果使用“混合”,则添加网格列或行时,控件将自动神奇地更改行/列规格,使其保持在原来的位置。

    希望有帮助。

    Expression Blend Trial

    更新:

    VS2012在WPF设计器中加入了许多Expression Blend功能。由于开发人员可以从Blend获得很多很酷的工具,因此不再需要Blend的副本。

        5
  •  2
  •   Johan Larsson    8 年前

    Here is a library for it

    <UserControl ...
                 xmlns:autoRowGrid="http://gu.se/AutoRowGrid"
                 ...>
        <autoRowGrid:Grid ColumnDefinitions="Auto *">
            <autoRowGrid:Row Name="first row">
                <TextBlock Text="foo1" />
                <TextBox Text="{Binding Value1}" />
            </autoRowGrid:Row>
    
            <autoRowGrid:Row Name="second row">
                <TextBlock Text="foo2" />
                <TextBox Text="{Binding Value2}" />
            </autoRowGrid:Row>
        </autoRowGrid:Grid>
        ...
    

    它是一个markupextension,返回一个香草WPF Grid

    NuGet

        6
  •  2
  •   SilverX    7 年前

    今天我看到这篇文章的时候也遇到了同样的问题,利用这篇文章中的答案,我想出了一个简单文本/文本对的可管理解决方案。要添加新字段,只需扩展“FormItems”集合。

    <Window.Resources>
        <c:ArrayList x:Key="FormItems">
            <c:DictionaryEntry Key="First        Name" Value="John"/>
            <c:DictionaryEntry Key="Last Name" Value="Smith"/>
        </c:ArrayList>
    </Window.Resources>
    
    <ItemsControl ItemsSource="{StaticResource FormItems}" Grid.IsSharedSizeScope="True">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock>
                        <Run Text="{Binding Key}"/><Run Text=": "/>
                    </TextBlock>
                    <TextBox Grid.Column="1" Text="{Binding Value}"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    Basic Form Layout Result

    编辑

    新建类:

    public class FormControlItem : ContentControl
    {
        public object Field {
            get { return base.GetValue(FieldProperty); }
            set { base.SetValue(FieldProperty, value); }
        }
    
        static FormControlItem() {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(FormControlItem), 
                new FrameworkPropertyMetadata(typeof(FormControlItem)));
        }
    
        public static readonly DependencyProperty FieldProperty =
            DependencyProperty.Register(
                "Field",
                typeof(object),
                typeof(FormControlItem),
                new FrameworkPropertyMetadata());
    }
    

    主题/Generic.xaml:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:local="clr-namespace:MyApplication">
    
    
        <Style TargetType="{x:Type local:FormControlItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:FormControlItem}">
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <ContentPresenter ContentSource="Field"/>
                                <ContentPresenter Grid.Column="1" ContentSource="Content"/>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    
    </ResourceDictionary>
    

    <ItemsControl Grid.IsSharedSizeScope="True">
        <local:FormControlItem Field="Name: ">
            <TextBox Text="{Binding Path=Name}"/>
        </local:FormControlItem>
        <local:FormControlItem Field="Type: ">
            <ComboBox 
                SelectedItem="{Binding Path=Type}"
                ItemsSource="{Binding Path=TypeValues}"/>
        </local:FormControlItem>
        <local:FormControlItem Field="Category: ">
            <TextBox Text="{Binding Path=Category}"/>
        </local:FormControlItem>
    </ItemsControl>
    

    Custom Control Layout Result

        7
  •  2
  •   Ryan_S    7 年前

    看看卡尔的东西。

    http://web.archive.org/web/20150620104259/https://karlshifflett.wordpress.com/2008/10/23/wpf-silverlight-lob-form-layout-searching-for-a-better-solution/

    简单干净的xaml:

    <pt:Form x:Name="formMain" Style="{DynamicResource standardForm}" Grid.Row="1">
      <TextBox pt:FormItem.LabelContent="_First Name" />
      <TextBox pt:FormItem.LabelContent="_Last Name"  />
      <TextBox pt:FormItem.LabelContent="_Phone" Width="150" HorizontalAlignment="Left" />
      <CheckBox pt:FormItem.LabelContent="Is _Active" />    
    </pt:Form>
    
        8
  •  0
  •   dex3703    14 年前

    在我们的产品中,我们使用HeaderedContentControl在网格中布局表单。控件模板有一个标签和填充/边距,以便控件的内容总是适当地间隔。在XAML中,我们只是将它们添加到列中。

    <Style x:Key="hccFormStyle" Targettype="{x:Type HeaderedContentControl}>
    ... some setters for colors, margin, padding, etc...
    <Setter Property="Template">
    <Setter.Value>
    <ControlTemplate>
      <Label Content={Binding Content} Target={Binding Tag}> <-- pass the control for the access key with the tag
      <ContentPresenter>
    </ControlTemplate>
    ...triggers if necessary - hover states, etc...
    </style>
    

    然后在网格中,定义行和列,并将其中一个放在每个单元格中,或放在每行的下面:

    <HeaderedContentControl x:Name="username" Grid.Column=0 Content="User Name" Tag=textboxUserName>
     <Textbox x:Name=textboxUserName>
    </HeaderedContentControl>
    

        9
  •  0
  •   Nir    14 年前

    我也遇到过同样的问题,在基于网格的布局中重新排序控件是一个真正的难题。

    所以我写了一个定制的面板,它可以进行“表单布局”(两列一组,所有标签大小相同,所有控件大小相同,所有内容对齐,等等),它在我的博客上: http://www.nbdtech.com/Blog/archive/2010/07/27/easy-form-layout-in-wpf-part-1-ndash-introducing-formpanel.aspx