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

如何使用网格或其他控件在WPF中布局表单以实现可维护性,wpf,forms,layout,grid,Wpf,Forms,Layout,Grid,我有一个WPF表格,我想在上面布置一个标准表格。每个表单元素将有一个标签,然后是一个控件。相当标准的东西 如果使用包裹面板,可能会导致标签和控件分离,但我希望它们保持在一起。是否存在与相当的WPF 网格工作,并允许列跨越等,但我真的很讨厌你指定每个控件上的列和行。这使得在列表中重新排序或插入内容非常不方便 有没有办法让网格使用更多HTML样式的列/行,其中项目是它们所在行的子行,以便我可以轻松地重新排序 是否有其他控件可以让我轻松地布局表单?尝试使用UniformGrid控件。您可能需要的是堆栈

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

如果使用包裹面板,可能会导致标签和控件分离,但我希望它们保持在一起。是否存在与
相当的WPF

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

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


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

尝试使用UniformGrid控件。

您可能需要的是堆栈面板。使用垂直堆叠面板将允许您一致地排列标签和控件。对于每个标签和控件,您可能需要这样一个水平堆栈面板

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

名称
出生日期
现在,您可以添加、删除、编辑和重新排序您的核心内容,而无需担心列和行

是否有一些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的冗长,尤其是你必须重复列定义。不过,如果你能正确地构造你的类并使用模板,那就没那么糟糕了。请注意,在这个方案中,任何地方都不会记录行号,因此对字段进行重新排序很简单。

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

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

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

希望能有帮助

在微软

更新:


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

查看Karl的资料

简单而干净的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>

在我们的产品中,我们使用一个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>

我也有同样的问题,在基于网格的布局中对控件重新排序是一件非常痛苦的事情

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

样本xaml:

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


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

xmlns:c=“clr命名空间:System.Collections;assembly=mscorlib”

Themes/Generic.xaml:

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());
}
<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>

用法示例:

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());
}
<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>


好看的代码。但是控件是用VB.NET编写的。你知道同样的情况吗,但是在C#中?看起来上面的站点已经不存在了。@AlexKlaus:如果它被编译成一个程序集,并且你想按原样使用控件,那么混合VB.NET和C#会有什么问题呢?很好的解决方案,但是你需要多少xaml,这是不礼貌的。还有性能方面的问题吗?为了获得更好的语法,请将宽度放在StackPanel.Resources中。