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

时间:2010-03-08 04:06:44

标签: wpf forms layout grid

我有一个WPF表单,我想在其上列出一个标准表单。每个表单元素都有一个标签,然后是一个控件。非常标准的东西。

如果我使用包装面板,它可能导致标签和控件分离,但我希望它们保持在一起。是否有一些WPF等效于<nobr/>

网格工作,并允许列跨越等,但我真的很讨厌你在每个控件上指定列和行。这使得将内容重新排序或插入列表非常不方便。

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

是否有其他控件可以让我轻松布局表单?

9 个答案:

答案 0 :(得分:20)

  

是否有一些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>

此外,对于柱状布局,Grid的共享大小范围可以协调使用它的任意数量的网格:

<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的冗长,特别是你必须重复列定义。虽然如果你正确地构建你的类并使用模板,它并不是那么糟糕。请注意,您不会在此方案中的任何位置跟踪行号,因此重新排序字段很简单。

答案 1 :(得分:6)

您可能正在寻找的是堆栈面板。使用垂直StackPanel可以一致地排列标签和控件。对于每个标签和控件,您可能需要一个像这样的水平堆栈面板

<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>

现在,您可以添加,删除,编辑和重新排序内容,而无需担心列和行。

答案 2 :(得分:5)

尝试使用UniformGrid控件。

答案 3 :(得分:2)

如果您能够给予它,我推荐Expression Blend,如果您要进行大量的UI设计。它允许更简单地查看项目。将控件嵌套到各种容器中是使UI动态化但结构化的好方法。

通常我会使用Grid面板将窗口分成功能区域。然后我将使用一系列StackPanels(通常是一个垂直的堆栈面板,里面有水平StackPanels,每个都有一个标签和文本框)。

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

希望它有所帮助。

Microsoft的

Expression Blend Trial

更新:

VS2012将很多Expression Blend功能融入WPF设计器中。由于开发人员可以访问Blend的许多很酷的工具,因此很多需要Blend的副本。

答案 4 :(得分:2)

查看卡尔的内容。

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>

答案 5 :(得分:2)

Here is a library for it

示例xaml:

Button*

这是一个markupextension,为一个漂亮的浅视觉树返回一个vanilla WPF <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> ...

NuGet

答案 6 :(得分:0)

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

我发布了一些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>

我可能会回答一个不同的问题,但这就是我们如何布置表格。

答案 7 :(得分:0)

我遇到了同样的问题,在基于网格的布局中重新排序控件真是太痛苦了。

所以我写了一个自定义面板,它做了“表单布局”(两列的组,所有标签大小相同,所有控件大小相同,所有内容都对齐等),它位于我的博客上:{{3} }

答案 8 :(得分:0)

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

的xmlns:C = “CLR-名称空间:System.Collections中;装配= mscorlib程序”

<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

没有考虑边距和填充,它只是显示了使用DataTemplate重用每个项目的布局的概念。它可以很容易地适应包括其他数据类型和控件。您甚至可以使用ItemTemplateSelector根据DictionaryEntry.Value的类型选择不同的模板

修改

我发现使DataBinding更容易的另一种方法是使用Visual Studio创建一个新的WPF“自定义控件”。这样做会创建一个名为Themes / Generic.xaml的新文件,并在其中定义新的默认布局。一些简单的编辑,我们可以使用ItemsControl来显示我们的新控件。

新课程:

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