views:

237

answers:

2

I normally program in C++, so all this DataSource/DataSet/Binding stuff is confusing the hell out of me. Hopefully you guys can help.

Basically I'm writing an editor for an XML-based file format (specifically, OFX, for financial data). I've used xsd.exe on my schema to deserialise loaded files into nice, plain old classes. I discovered DataGridView, which is brilliant, which I can just set its DataSource property to one of the collections I'm interested in (specifically, the list of transactions), and when I poke around with the values these changes get reflected in the loaded deserialised file, which I can then serialise out on save. But when I want to 'map' just a simple string to a TextBox (e.g. the account number), I can't use this clever method at TextBoxes don't seem to have a DataSource member... Using their 'Text' property just sets the text once and doesn't reflect changes back to the underlying object, so saving has to grab the values from the control first. I'd like it to be automatic like for the DataGridView.

I've tried fiddling with the DataBindings but I have no idea what to use as the propertyName or dataMember, so I'm not sure if that's what I'm meant to be using:

accountNumberTextBox.DataBindings.Add(new Binding("???", myDocument.accountNumber, "???");

Am I missing something really obvious? I hope so!

+1  A: 
accountNumberTextBox.DataBindings.Add("Text",
                                      myDocumnt.Tables["your_table"],
                                      "table_field");

Example,

DataSet ds = new DataSet("DB");
DataTable dt = new DataTable("myTable");
dt.Columns.Add("Name");
dt.Rows.Add("PP");
dt.Rows.Add("QQ");
ds.Tables.Add(dt);

textBox1.DataBindings.Add("Text", ds.Tables["myTable"], "Name");
adatapost
That's what I don't get; all the DataSet/DataTable stuff. I've effectively just got a string I want to use as a DataSource; do I need to put that in a one-column, one-row DataTable in a one-table DataSet to look it up?
Ben Hymers
+2  A: 

What you're missing is that strings are immutable in .NET. Thus, for a binding to make any sense the string value needs to be encapsulated by something else. The data binding system then replaces the existing string with a new one when the user enters a value.

The something else that encapsulates the string can be a DataTable or a plain old class that includes change notification. The best way to provide this change notification is to implement the INotifyPropertyChanged interface.

For example:

public class Document : INotifyPropertyChanged
{
    private string _accountNumber;

    public string AccountNumber
    {
        get { return _accountNumber; }
        set
        {
            if (_accountNumber != value)
            {
                _accountNumber = value;
                //this tells the data binding system that the value has changed, so the interface should be updated
                OnPropertyChanged("AccountNumber");
            }
        }
    }

    //raised whenever a property value on this object changes. The data binding system attaches to this event
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged:

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

So, your data binding hook-up would look like this:

var document = ...; //get document from somewhere
//bind the Text property on the TextBox to the AccountNumber property on the Document
textBox1.DataBindings.Add("Text", document, "AccountNumber");

HTH, Kent

Kent Boogaart
Ah, the problem with that is that the class containing the string I want to bind is generated. Is there a way to do this less intrusively?
Ben Hymers
@Pierre: thanks, fixed
Kent Boogaart
@Ben: you can either generate the change notification logic, or write a class that wraps your data object and adds change notification for the purposes of data binding in the UI.
Kent Boogaart