以编程方式将控件添加到WPF表单中 [英] Programmatically Add Controls to WPF Form

查看:132
本文介绍了以编程方式将控件添加到WPF表单中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试向用户控件添加动态(编程)控件。我从我的业务层(从数据库检索)中得到一个通用的对象列表,对于每个对象,我想添加一个Label和一个TextBox到WPF UserControl,并设置位置和宽度看起来很好,希望利用WPF验证功能。这在Windows窗体编程中很容易,但我是WPF的新手。如何做到这一点(见问题的评论)说这是我的对象:

I am trying to add controls to a UserControl dynamically (programatically). I get a generic List of objects from my Business Layer (retrieved from the database), and for each object, I want to add a Label, and a TextBox to the WPF UserControl and set the Position and widths to make look nice, and hopefully take advantage of the WPF Validation capabilities. This is something that would be easy in Windows Forms programming but I'm new to WPF. How do I do this (see comments for questions) Say this is my object:

public class Field {
   public string Name { get; set; }
   public int Length { get; set; }
   public bool Required { get; set; }
}

然后在我的WPF UserControl中,我试图创建一个Label和每个对象的TextBox:

Then in my WPF UserControl, I'm trying to create a Label and TextBox for each object:

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 ,以便您可以获得数据绑定和动态生成的所有好处。因此,我们将使用 ItemsControl.ItemsPanel 属性,这允许我们指定项目将被放入的面板。我们从代码隐藏开始:

Alright, second time's the charm. Based on your layout screenshot, I can infer right away that what you need is a WrapPanel, a layout panel that allows items to fill up until it reaches an edge, at which point the remaining items flow onto the next line. But you still want to use an ItemsControl so you can get all the benefits of data-binding and dynamic generation. So for this we're going to use the ItemsControl.ItemsPanel property, which allows us to specify the panel the items will be put into. Let's start with the code-behind again:

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

这里没有太多变化,但是我已经将示例字段编辑为比较适合你的例子现在让我们来看看魔术发生的地方 - XAML为 Window

Not much has changed here, but I've edited the sample fields to better match your example. Now let's look at where the magic happens- the XAML for the Window:

<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 稍有变化。标签仍然绑定到名称属性,但现在文本框宽度绑定到length属性(因此您可以具有不同长度的文本框)。此外,我已经使用一个简单的 BoolToVisibilityConverter (可以在任何地方找到代码,并且我不会在这里发布)的任何字段添加了一个* )

First, you will notice that the ItemTemplate has changed slightly. The label is still bound to the name property, but now the textbox width is bound to the length property (so you can have textboxes of varying length). Furthermore, I've added a "*" to any fields that are required, using a simplistic BoolToVisibilityConverter (which you can find the code for anywhere, and I will not post here).

要注意的主要事情是在 ItemsPanel中使用 WrapPanel 属性我们的 ListBox 。这告诉 ListBox ,它生成的任何项目都需要被推入水平包装的布局(这符合你的屏幕截图)。什么使这个工作更好的是面板上的高度和宽度绑定 - 这是什么,使这个面板与我的父窗口大小相同。这意味着当我调整 Window 的大小时, WrapPanel 相应调整其大小,从而为项目布局更好。这两个屏幕截图显示了这一点:

The main thing to notice is the use of a WrapPanel in the ItemsPanel property of our ListBox. This tells the ListBox that any items it generates need to be pushed into a horizontal wrapped layout (this matches your screenshot). What makes this work even better is the height and width binding on the panel- what this says is, "make this panel the same size as my parent window." That means that when I resize the Window, the WrapPanel adjusts its size accordingly, resulting in a better layout for the items. The two screenshots here demonstrate this:

alt text http: //img156.imageshack.us/img156/6849/wrappanelfields.png

alt text http://img12.imageshack.us/img12/2426/wrappanelfields2.png

这篇关于以编程方式将控件添加到WPF表单中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆