wpf - 以编程方式将控件添加到 WPF 表单

标签 wpf dynamic controls

我正在尝试动态(以编程方式)将控件添加到 UserControl。我从我的业务层(从数据库中检索)获得了一个通用的对象列表,对于每个对象,我想向 WPF 用户控件添加一个标签和一个文本框,并设置位置和宽度以使其看起来不错,并希望利用 WPF 验证功能。这在 Windows 窗体编程中很容易,但我是 WPF 新手。我该怎么做(请参阅问题评论)说这是我的对象:

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

最佳答案

好吧,第二次是魅力。根据您的布局屏幕截图,我可以立即推断出您需要的是 WrapPanel ,一个布局面板,允许项目填充直到它到达边缘,此时剩余的项目流到下一行。但是您仍然想使用 ItemsControl因此您可以获得数据绑定(bind)和动态生成的所有好处。所以为此我们将使用 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略有变化。标签仍然绑定(bind)到名称属性,但现在文本框宽度绑定(bind)到长度属性(因此您可以拥有不同长度的文本框)。此外,我使用简单的 BoolToVisibilityConverter 在任何必填字段中添加了一个“*”。 (你可以在任何地方找到代码,我不会在这里发布)。

主要需要注意的是 WrapPanel 的使用。在 ItemsPanel我们 ListBox 的属性(property).这告诉 ListBox它生成的任何项目都需要推送到水平包装的布局中(这与您的屏幕截图相匹配)。使这项工作变得更好的是面板上的高度和宽度绑定(bind)——这就是说,“使这个面板与我的父窗口大小相同”。这意味着当我调整 Window 的大小时, WrapPanel相应地调整其大小,从而为项目提供更好的布局。

关于wpf - 以编程方式将控件添加到 WPF 表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2814866/

相关文章:

.net - Wpf ListBoxes' ItemsSource 奇怪的行为

c# - 管理表单状态的最佳方法是什么?

Java Applet 导致 .NET Webbrowsercontrol 崩溃

c# - 单击下拉列表的箭头/延迟加载下拉列表加载下拉列表

c# - 寻找有关在 WPF MVVM 应用程序中放置一些代码的指导

.net - WPF 是 Windows 应用程序的选择吗?

c# - 嵌套 for 循环的动态数量,用于列出对象的唯一组合

c# - 如何在不知道所有参数的情况下动态调用对象的构造函数?

sql - 从函数调用动态SQL

c# - 使用 Caliburn 的 TextboxHelper.ButtonCommand 绑定(bind)