以编程方式将控件添加到 WPF 表单
Posted
技术标签:
【中文标题】以编程方式将控件添加到 WPF 表单【英文标题】:Programmatically Add Controls to WPF Form 【发布时间】:2011-02-18 09:10:24 【问题描述】:我正在尝试动态(以编程方式)将控件添加到 UserControl。我从我的业务层(从数据库中检索)获得了一个通用的对象列表,对于每个对象,我想向 WPF 用户控件添加一个标签和一个文本框,并设置位置和宽度以使其看起来不错,并希望利用 WPF 验证功能。这在 Windows 窗体编程中很容易,但我是 WPF 新手。我该怎么做(请参阅 cmets 了解问题)说这是我的对象:
public class Field
public string Name get; set;
public int Length get; set;
public bool Required get; set;
然后在我的 WPF UserControl 中,我尝试为每个对象创建一个标签和文本框:
public void createControls()
List<Field> fields = businessObj.getFields();
Label label = null;
TextBox textbox = null;
foreach (Field field in fields)
label = new Label();
// HOW TO set text, x and y (margin), width, validation based upon object?
// i have tried this without luck:
// Binding b = new Binding("Name");
// BindingOperations.SetBinding(label, Label.ContentProperty, b);
MyGrid.Children.Add(label);
textbox = new TextBox();
// ???
MyGrid.Children.Add(textbox);
// databind?
this.DataContext = fields;
【问题讨论】:
【参考方案1】:好的,第二次是魅力。根据您的布局屏幕截图,我可以立即推断出您需要的是WrapPanel
,这是一个布局面板,允许项目填充直到它到达边缘,此时剩余的项目流到下一行。但是您仍然想使用ItemsControl
,这样您就可以获得数据绑定和动态生成的所有好处。所以为此我们将使用ItemsControl.ItemsPanel
属性,它允许我们指定项目将被放入的面板。让我们再次从代码隐藏开始:
public partial class Window1 : Window
public ObservableCollection<Field> Fields get; set;
public Window1()
InitializeComponent();
Fields = new ObservableCollection<Field>();
Fields.Add(new Field() Name = "Username", Length = 100, Required = true );
Fields.Add(new Field() Name = "Password", Length = 80, Required = true );
Fields.Add(new Field() Name = "City", Length = 100, Required = false );
Fields.Add(new Field() Name = "State", Length = 40, Required = false );
Fields.Add(new Field() Name = "Zipcode", Length = 60, Required = false );
FieldsListBox.ItemsSource = Fields;
public class Field
public string Name get; set;
public int Length get; set;
public bool Required get; set;
这里没有太大变化,但我编辑了示例字段以更好地匹配您的示例。现在让我们看看魔法发生在哪里——Window
的 XAML:
<Window x:Class="DataBoundFields.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataBoundFields"
Title="Window1" Height="200" Width="300">
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
</Window.Resources>
<Grid>
<ListBox x:Name="FieldsListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="Binding Name" VerticalAlignment="Center"/>
<TextBox Width="Binding Length" Margin="5,0,0,0"/>
<Label Content="*" Visibility="Binding Required, Converter=StaticResource BoolToVisConverter"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"
Height="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type Window, Path=ActualHeight"
Width="Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type Window, Path=ActualWidth"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
首先,您会注意到ItemTemplate
略有变化。标签仍然绑定到 name 属性,但现在文本框宽度绑定到 length 属性(因此您可以拥有不同长度的文本框)。此外,我还使用简单的BoolToVisibilityConverter
在任何必填字段中添加了“*”(您可以在任何地方找到代码,我不会在这里发布)。
主要需要注意的是WrapPanel
在我们的ListBox
的ItemsPanel
属性中的使用。这告诉ListBox
它生成的任何项目都需要被推送到水平包装布局中(这与您的屏幕截图相符)。使这项工作变得更好的是面板上的高度和宽度绑定——这就是说,“使这个面板与我的父窗口大小相同”。这意味着当我调整Window
的大小时,WrapPanel
会相应地调整其大小,从而为项目带来更好的布局。
【讨论】:
+1,但我认为 OP 想要 Length 和 Required 来约束输入。 当然可以,但我不确定他到底想如何使用这些约束,所以我没有使用它们。 麻烦是——我可能会因为使用变量名“MyGrid”而混淆了问题——我将它们添加到我会听查理和乔比的回答,但为了直接回答问题……(如何添加控件并手动定位它们。)
使用Canvas
控件,而不是Grid
。画布为控件提供了无限的空间,并允许您手动定位它们。它使用附加属性来跟踪位置。在代码中,它看起来像这样:
var tb = new TextBox();
myCanvas.Children.Add(tb);
tb.Width = 100;
Canvas.SetLeft(tb, 50);
Canvas.SetTop(tb, 20);
在 XAML 中...
<Canvas>
<TextBox Width="100" Canvas.Left="50" Canvas.Top="20" />
</Canvas>
您还可以相对于右边缘和下边缘定位它们。同时指定 Top 和 Bottom 将使控件随 Canvas 垂直调整大小。 Left 和 Right 也是如此。
【讨论】:
【参考方案3】:不建议添加这样的控件。您在 WPF 中理想的做法是放置一个 ListBox(或 ItemsControl)并将您的业务对象集合绑定为 itemsControl.ItemsSource 属性。现在在 XAML 中为您的 DataObject 类型定义 DataTemplate,您就可以开始了,这就是 WPF 的魔力。
来自 winforms 背景的人倾向于按照您描述的方式进行操作,这在 WPF 中是不正确的。
【讨论】:
+1。很少有事情我愿意直截了当地说:“这是错误的。”使用正则表达式解析 XML 就是其中之一。在 WPF 应用程序中使用 WinForms 技术是另一回事。以上是关于以编程方式将控件添加到 WPF 表单的主要内容,如果未能解决你的问题,请参考以下文章
如何通过行和列索引以编程方式访问 WPF Grid 中的控件?