使用 C# 以单一形式动态创建多个文本框?

Create multiple textbox dynamically in single form using c#?

我的目标是动态创建一个包含 TextBox、Button 的 .dll 文件,任何人都可以在使用 Visual C# 的程序中使用它。

它将在 Class 库中创建,不会使用 WFA 工具。

我需要帮助创建一个可以根据用户提供的属性生成多个 TextBox 的表单。

1)文本框数量 2)地点 3)尺寸等

代码

CLASS.CS

 using System;
 using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.IO;


namespace Forms
{
public class TextForm : Form
{
    public TextBox txtBox1;        
    public TextForm(int a, int b, int c, int d, string e)
    {

        Form f1 = new Form();
        txtBox1 = new TextBox();
        txtBox1.Visible = true;
        //f1.ActiveControl=txtBox1;
        f1.Controls.Add(txtBox1);
        txtBox1.Focus();
        f1.Visible = true;
            txtBox1.Size = new Size(a, b);
            txtBox1.Location = new Point(c, d);
            txtBox1.Text = (e).ToString();
            this.Controls.Add(txtBox1);
            txtBox1.Visible = true;

    }
    [STAThread]
    static void Main()
    { 
        Application.EnableVisualStyles();
    }
  }}

PROGRAM.CS

using System;
using Forms;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
class Program
{

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        TextForm Box1 = (new TextForm(150, 14, 20, 32, "This is a TextBox 1"));
        TextForm Box2 = (new TextForm(180, 34, 40, 52, "This is a TextBox 2"));

    }}}

代码应该是什么?

如果您愿意切换到 WPF,这将变得容易得多,因为您可以从自动布局和绑定中获益。

您可以轻松地将 Wrappanel 切换为 StackPanel 或 DockPanel。

class会根据移交对象的public属性创建View。您可能必须向 Types-Dictionary 添加其他类型。就我而言,这两个就足够了。

创建 DynamicControl 的 属性 并绑定到 XAML。

XAML:
<ContentPresenter Content="{Binding Path=DynView}" />

public ViewModel
{
  public UserControl DynView {get; private set};

  private ModelType _model;

  public ViewModel(ModelType model)
  {
    _model = model;
    DynView = new DynamicControl<ModelType>(_model);
  }

}

public class DynamicControl<T> : UserControl 
{

    static DynamicControl()
    {
        Types[typeof(bool)] = (binding) =>
        {
            CheckBox cb = new CheckBox();
            cb.SetBinding(CheckBox.IsCheckedProperty,binding);
            return cb;
        };

        Types[typeof(String)] = (binding) =>
        {
            TextBox tb = new TextBox();
            tb.SetBinding(TextBox.TextProperty, binding);
            return tb;
        };

       // add additional Types if necessary
    }

    private T _model; 
    public DynamicControl(T model)
    {
        _model = model;
        WrapPanel wp = new WrapPanel();
        foreach (PropertyInfo pi in model.GetType().GetProperties())
        {
            Grid g = new Grid();
            g.Margin = new Thickness(5, 5, 25, 5);
            g.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            g.ColumnDefinitions.Add(new ColumnDefinition());
            g.ColumnDefinitions.Add(new ColumnDefinition());
            g.RowDefinitions.Add(new RowDefinition());
            TextBlock tb = new TextBlock() { Text = pi.Name };
            tb.VerticalAlignment = VerticalAlignment.Center;
            Grid.SetColumn(tb, 0);
            Grid.SetRow(tb, 0);
            g.Children.Add(tb);
            System.Windows.FrameworkElement uie = GetUiElement(pi);
            uie.Margin = new Thickness(10, 0, 0, 0);
            uie.VerticalAlignment = VerticalAlignment.Center;
            Grid.SetColumn(uie, 1);
            Grid.SetRow(uie, 0);
            g.Children.Add(uie);
            wp.Children.Add(g);
        }
        this.Content = wp;
    }

    private FrameworkElement GetUiElement(PropertyInfo pi)
    {
        System.Windows.Data.Binding binding = new System.Windows.Data.Binding(pi.Name);
        binding.Source = _model;
        Func<System.Windows.Data.Binding, FrameworkElement> func;
        FrameworkElement uie = null;
        if (Types.TryGetValue(pi.PropertyType, out func))
            uie = func(binding);
        else
            uie = Types[typeof(String)](binding);

        return uie;
    }

    private static Dictionary<Type, Func<System.Windows.Data.Binding, FrameworkElement>> Types = new Dictionary<Type, Func<System.Windows.Data.Binding, FrameworkElement>>();
}

问题是您正在为每个 TextBox 创建一个 Form。这不是您想要的,前提是您计划拥有包含多个文本框的表单。

我看到了两种可能性:您想要创建 a) 可以轻松添加到表单中的文本框,或者 b) 带有文本框的表单。

public class TextInput : Form
{
    public TextBox TxtBox {
        get; private set;
    }

    public Control Container {
        get; private set;
    }

    public TextInput(Control c, int a, int b, int c, int d, string e)
    {
        this.Container = c;
        this.TxtBox = new TextBox();

        var txtBox1 = this.TxtBox;
        txtBox1.Visible = true;
        c.Controls.Add(txtBox1);
        txtBox1.Focus();
        txtBox1.Size = new Size(a, b);
        txtBox1.Location = new Point(c, d);
        txtBox1.Text = (e).ToString();
        txtBox1.Visible = true;
    }
}

您可以按如下方式使用它:

var f = new Form();
var txtBox1 = new TextInput( f, 100, 25, 10, 10, "Name" );
var txtBox1 = new TextInput( f, 100, 25, 10, 50, "Age" );
var txtBox1 = new TextInput( f, 100, 25, 10, 100, "Address" );
var txtBox1 = new TextInput( f, 100, 25, 10, 150, "Phone" );

在我看来,第二种可能性更有趣。您想要创建一个特殊的表单,只要您调用一个简单的方法,它就会自动添加文本框。不过,我将简化您的代码。在表单中使用绝对定位(根本)不是一个好主意。

下面创建了一个带有文本框及其标签的表单。文本框占据了表单的整个宽度。这是通过使用 TableLayoutPanel 实现的,其中每行使用 Panel subPanel。 此 子面板 包含一个标签和一个文本框。

public class InputForm: Form {
        public InputForm()
        {
            this.Panel = new TableLayoutPanel{ Dock = DockStyle.Fill };            
            this.textBoxes = new List<TextBox>();
            this.Controls.Add( this.Panel );
        }

        public TextBox AddTextBox(string label)
        {
            var subPanel = new Panel { Dock = DockStyle.Top };
            var lblLabel = new Label { Text = label, Dock = DockStyle.Left };
            var tbEdit = new TextBox{ Dock = DockStyle.Fill };

            subPanel.Controls.Add( tbEdit );
            subPanel.Controls.Add( lblLabel );
            this.Panel.Controls.Add( subPanel );

            return tbEdit;
        }

        public TableLayoutPanel Panel {
            get; private set;
        }

        public TextBox[] TextBoxes {
            get {
                return this.textBoxes.ToArray();
            }
        }

        private List<TextBox> textBoxes;
    }

您可以通过以下简单代码使用它:

        var form = new InputForm();

        var tbName = form.AddTextBox( "Name" );
        var tbAge = form.AddTextBox( "Age" );
        var tbAddress = form.AddTextBox( "Address" );

        form.Show();
        Application.Run( form );

如果您想为要创建的文本框指定一些属性(颜色、字体、粗体...),那么您有两种方法。第一个是向 AddTextBox() 方法添加参数,但随着属性数量的增加,这种方法不会很好地扩展。另一种方法是创建一个 TextBoxAttributes class,它将保存给定 TextBox.

的配置属性
public class InputForm: Form {
    public class TextBoxAttributes {
        public TextBoxAttributes() {
            this.ForeColor = DefaultForeColor;
            this.BackColor = DefaultBackColor;
            this.Font = DefaultFont;
        }

        public Color ForeColor {
            get; set;
        }

        public Color BackColor {
            get; set;
        }

        public Font Font {
            get; set;
        }

        public bool Bold {
            get {
                return this.Font.Bold;
            }
            set {
                var style = FontStyle.Regular;

                if ( value ) {
                    style = FontStyle.Bold;
                }

                this.Font = new Font( this.Font, style );
            }
        }

        public bool Italic {
            get {
                return this.Font.Bold;
            }
            set {
                var style = FontStyle.Regular;

                if ( value ) {
                    style = FontStyle.Italic;
                }

                this.Font = new Font( this.Font, style );
            }
        }

        public bool Underline {
            get {
                return this.Font.Bold;
            }
            set {
                var style = FontStyle.Regular;

                if ( value ) {
                    style = FontStyle.Underline;
                }

                this.Font = new Font( this.Font, style );
            }
        }

        public float FontSize {
            get {
                return this.Font.Size;
            }
            set {
                this.Font = new Font( this.Font.FontFamily, value );
            }
        }
    }

    // ... more things...

    public TextBox AddTextBox(string label)
        => this.AddTextBox( label, new TextBoxAttributes() );

    public TextBox AddTextBox(string label, TextBoxAttributes attr)
    {
        var subPanel = new Panel { Dock = DockStyle.Top };
        var lblLabel = new Label { Text = label, Dock = DockStyle.Left };
        var tbEdit = new TextBox{
            Dock = DockStyle.Fill,
            ForeColor = attr.ForeColor,
            BackColor = attr.BackColor,
            Font = attr.Font
        };

        subPanel.Controls.Add( tbEdit );
        subPanel.Controls.Add( lblLabel );
        this.Panel.Controls.Add( subPanel );

        return tbEdit;
    }

    // ... more things...
}

主要代码为:

        public static void Main()
        {
            var form = new InputForm();

            var tbName = form.AddTextBox( "Name", new InputForm.TextBoxAttributes {
                ForeColor = Color.Yellow,
                BackColor = Color.Blue
            });
            var tbAge = form.AddTextBox( "Age", new InputForm.TextBoxAttributes {
                ForeColor = Color.Green,
                BackColor = Color.Black,
                Bold = true
            });
            var tbAddress = form.AddTextBox( "Address" );

            form.Show();
            Application.Run( form );
        }

希望这对您有所帮助。

我认为你的做法完全错了。只需预先定义尺寸和文本,将它们放入数据 class 中,然后将这些数据的列表 class 提供给表单构造函数,以便它可以即时构建它们。

数据class:

public class TextboxInfo
{
    public Int32 Width { get; set; }
    public Int32 Height { get; set; }
    public Int32 X { get; set; }
    public Int32 Y { get; set; }
    public String Text { get; set; }

    public TextboxInfo(Int32 w, Int32 h, Int32 x, Int32 y, String text)
    {
        this.Width = w;
        this.Height = h
        this.X = x;
        this.Y = y
        this.Text = text;
    }
}

构造表单的代码:

public class TextForm : Form
{
    public TextBox[] TextBoxes
    {
         get { return _textBoxes.ToArray(); }
    }
    private List<TextBox> _textBoxes;

    public TextForm(TextboxInfo[] textboxes, Int32 padX, Int32 padY)
    {
        _textBoxes = new List<TextBox>();
        Int32 reqWidth = 0;
        Int32 reqHeight = 0;
        foreach (TextboxInfo tbi in textboxes)
        {
            reqWidth = Math.Max(reqWidth, tbi.X + tbi.Width);
            reqHeight = Math.Max(reqHeight, tbi.Y + tbi.Height);
            TextBox txtB = new TextBox();
            txtB.Size = new Size(tbi.Width, tbi.Height);
            txtB.Location = new Point(tbi.X, tbi.Y);
            txtB.Text = tbi.Text;
            _textBoxes.Add(txtB);
            this.Controls.Add(txtB);
        }
        // You may want to add some kind of OK button at the end here (based on reqHeight)
        // and link that to a click listener that closes the form.
        // Don't forget to adjust your reqHeight to the added height of that button!

        // ...

        // Set form to the minimum needed size according to its elements.
        this.Size = new Size(reqWidth + padX, reqHeight + padY);
    }
}

调用代码:

class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        TextboxInfo[] info = new TextboxInfo[2];
        info[0] = new TextboxInfo(150, 14, 20, 32, "This is a TextBox 1");
        info[1] = new TextboxInfo(180, 34, 40, 52, "This is a TextBox 2");
        TextForm frm = new TextForm(info, 20, 32);
        frm.ShowDialog();
        // Now you can access the form's text box values through frm.TextBoxes[i].Text
    }
}

请注意,整个系统乍一看似乎很有用,但请考虑 none 个文本框上有标签。刚开始的值。

我之前在创建的项目中为自定义数据制作过系统,以根据选择的要保存到的文件类型生成自定义保存选项对话框,因为每种文件类型都需要特定的选项。

实际上,您会创建一个表单,顶部有某种描述,底部有确定按钮和取消按钮,中间有一个面板,其垂直滚动条设置为在需要时启用。然后您可以动态地在其中放置不同的自定义控件以支持不同的数据类型,例如复选框、文本字段、数字字段等。它们将自动在列表中垂直列出,只需跟踪每个控件的高度以获得下一个控件的 Y 偏移量,如果它们超过表单大小,面板将确保您可以向下滚动。

您为表单提供的只是数据对象 class 就像我展示的那样,但没有定位数据。他们有一个类型,用来确定要创建什么样的自定义控件,一个描述文本,一个将输入控件设置为的默认值,以及可能的某种初始化值,例如,限制一个数字的范围值,或者,如我显示的图像,下拉列表的值。