C# Winforms - bind textbox to array element from class

1.7k views Asked by At

I'm currently trying to bind an array element from a class to a text box without success.

class Test{
   ...
   string[] toto = new string[]{"element1"};
}

Test test;
void form_load()
{
   test = new Test();
   textBox1.DataBinding.Add("Text", test, "toto(0)");
}

(I tried as discussed here : Winforms Databinding to element in array)

But I get :

System.ArgumentException: 'Cannot bind to the property or column Requires(0) on the DataSource. Parameter name: dataMember'

If I bind it like this:

checkBox2.DataBindings.Add(new Binding("Checked", config.Requires[0], ""));

It works but I can't implement INotifyPropertyChanged for updating the form on change perform by the code.

Does anyone have any idea?

Edit: After binding, the form should be updated when the element of the array is updated.

2

There are 2 answers

4
Joshua Robinson On BEST ANSWER

Quite possibly there is a better way to do this, but what you could do is create an instance of BindingSource for each element in the array, set the BindingSource.Position property, then set that as the binding for the TextBox.

Edit: Made the Data Binding 2-way... changing the value in the control updates the object, changing the value from the object changes the control.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Test
{
   public class Foo
   {
      public Foo()
      {
         Items = new BindingList<string>();
      }

      public IList<string> Items { get; private set; }
   }

   static class Program
   {
      /// <summary>
      /// The main entry point for the application.
      /// </summary>
      [STAThread]
      static void Main()
      {
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);

         _dataSource.Items.Add("Value");
         _dataSource.Items.Add("Value 2");
         _dataSource.Items.Add("Value 3");

         var frm = new Form();

         var flp = new FlowLayoutPanel
         {
            Dock = DockStyle.Fill,
            FlowDirection = FlowDirection.TopDown
         };

         for (int i = 0; i < _dataSource.Items.Count; i++)
         {
            var bs = new BindingSource(_dataSource, "Items");
            bs.Position = i;
            var tb = new TextBox();
            tb.DataBindings.Add("Text", bs, "");
            flp.Controls.Add(tb);
         }
         frm.Controls.Add(flp);

         var btn = new Button()
         {
            Text = "Show Object's Values",
            Dock = DockStyle.Bottom
         };
         btn.Click += btn_Click;
         frm.Controls.Add(btn);

         var btn2 = new Button()
         {
            Text = "Change Object's Values",
            Dock = DockStyle.Bottom
         };
         btn2.Click += btn2_Click;
         frm.Controls.Add(btn2);

         Application.Run(frm);
      }

      static void btn_Click(object sender, EventArgs e)
      {
         MessageBox.Show(string.Join(Environment.NewLine, _dataSource.Items.ToArray()));
      }

      static void btn2_Click(object sender, EventArgs e)
      {
         var rng = new Random();
         for (int i = 0; i < _dataSource.Items.Count; i++)
         {
            var b = new byte[8];
            rng.NextBytes(b);
            _dataSource.Items[i] = Convert.ToBase64String(b);
         }
      }

      static Foo _dataSource = new Foo();
   }
}
1
Zen Zac On

You could create a property as follows:

private string _element1;
public string Element1
{
  get
  {
    return _element1;
  }
  set 
  {
   element1 = value;
    OnPropertyChanged(nameof(Element1));
  }
}

Set it as: Element1 = config.Requires[0]; And then use it to set the TextBox as follows: checkBox2.DataBindings.Add(new Binding("Checked", Element1, ""));