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