Unbound Sources

  • 7 minutes to read

The UnboundSource component is designed for unconventional binding scenarios when no strongly typed data set is available. The event-based nature of this component allows you to manually control what data is loaded into a data-aware control and how changes are saved.

Connect a Control to UnboundSource using the Data Source Configuration Wizard

The Data Source Configuration Wizard is the most handy way of binding DevExpress data-aware controls to any supported data source type. In this article, binding the Data Grid is taken as an example.

  1. Invoke the wizard by clicking the icon in the Data Grid control's bottom left corner.

    Unbound DS - Invoke Wizard

  2. Select the "Unbound Data Source" option. The list on the wizard's right will display any existing unbound sources. You can select one of them or click the "New Data Source..." button, then click "Next" to proceed.

  3. If you have selected an existing UnboundSource, the wizard will ask you to set the row count for this source. This value sets the total number of records your data-aware component will receive.

    UnboundSource - RowCount

    Otherwise, if you have created a new source, you will see a Collection Editor dialog instead. Utilize this dialog to create data fields for the UnboundSource component. For the sample data used in this example, you will need to create two data fields - "Int" and "String".

    Unbound DS - Collection Editor

  4. Customize your data-aware control in accordance with the data fields added to the UnboundSource component. For the Data Grid control, you need to create a GridColumn for each data field. The most convenient way to do so is to invoke the Grid Designer, switch to its "Columns" tab and click the "Retrieve Fields" button.

    Unbound DS - Retrieve Fields

  5. Handle the ValueNeeded/ValuePushed events to supply your grid with data and save modified data to storage.

Connect a Control to UnboundSource Manually

You can use the UnboundSource component directly to bind any third-party data-aware control that cannot be bound using the Data Source Configuration Wizard.

  1. Drop the UnboundSource component onto your form.
  2. Locate the Properties line in Visual Studio's Property Grid and click its ellipsis button. This will invoke the Collection Editor dialog. Using this dialog, create data fields that match your existing data source. For the sample data used in this example, you will need to create two data fields - "Int" and "String".

    UnboundSource - Invoke CE and Create Fields

  3. Set your UnboundSource component as a data source for the required data-aware control.

    UnboundSource - Set DataSource

  4. Customize the data-aware control according to data source fields. For Data Grid, you will need to create two GridColumn objects and specify their GridColumn.FieldName properties to match your data fields. The most convenient way to do so is to invoke the Grid Designer, switch to its "Columns" tab and click the "Retrieve Fields" button.

    Unbound DS - Retrieve Fields

  5. Use the component's SetRowCount method to specify the initial amount of data source records.

    
    unboundSource1.SetRowCount(Employees.Count);
    
  6. Handle the ValueNeeded/ValuePushed events to supply your grid with data and save modified data to storage.

Handle Data Requests and Updates

NOTE

Show Me The complete sample project is available in the DevExpress Code Examples database at http://www.devexpress.com/example=T474976.

After a control has been connected to UnboundSource, you need to transfer data to the control from the source. For this task UnboundSource raises the ValueNeeded event. This event will fire multiple times depending on the UnboundSource RowCount property value. The separate ValuePushed event allows you to save the modified control data back to storage.

The code below illustrates how to fetch data to the control from the "DefaultStringData" array and write modified data portions to the "Differences" dictionary.


//a source with initial control data
readonly string[] DefaultStringData = CultureInfo.CurrentCulture.DateTimeFormat.DayNames;

//a source for modified control data
readonly Dictionary<CellKey, object> Differences = new Dictionary<CellKey, object>();

//this custom structure allows you to compare control data with dictionary entries
private struct CellKey : IEquatable<CellKey> {
    int rowIndex;
    string propertyName;
    public int RowIndex { get { return rowIndex; } }
    public string PropertyName { get { return propertyName; } }
    public CellKey(int rowIndex, string propertyName) {
        this.rowIndex = rowIndex;
        this.propertyName = propertyName;
    }
    public bool Equals(CellKey other) {
        return this.RowIndex == other.RowIndex && this.PropertyName == other.PropertyName;
    }
    public override int GetHashCode() {
        return unchecked(RowIndex * 257 + (string.IsNullOrEmpty(this.PropertyName) ? 0 : this.PropertyName[0]));
    }
    public override bool Equals(object obj) {
        if(obj is CellKey)
            return Equals((CellKey)obj);
        else
            return false;
    }
}

//load 100.000 records
unboundDS.SetRowCount(100000);

//retrieve records from the array
object GetDefaultData(int rowIndex, string propertyName) {
    switch(propertyName) {
        case "String":
            return DefaultStringData[rowIndex % DefaultStringData.Length];
        case "Int":
            return rowIndex + 1;
        default:
            return null;
    }
}

//provide data to a control
void unboundDS_ValueNeeded(object sender, UnboundSourceValueNeededEventArgs e) {
    if(this.Differences.Count > 0) {
        object rv;
        //if the dictionary contains modified data for the current cell, it will be taken
        if(this.Differences.TryGetValue(new CellKey(e.RowIndex, e.PropertyName), out rv)) {
            e.Value = rv;
            return;
        }
    }
    //otherwise, a control will receive default data from the array
    e.Value = GetDefaultData(e.RowIndex, e.PropertyName);
}

//push modified data to the dictionary
void unboundDS_ValuePushed(object sender, UnboundSourceValuePushedEventArgs e) {
    var defaultValue = GetDefaultData(e.RowIndex, e.PropertyName);
    var cellKey = new CellKey(e.RowIndex, e.PropertyName);
    if(object.Equals(defaultValue, e.Value))
        this.Differences.Remove(cellKey);
    else
        this.Differences[cellKey] = e.Value;
}

To remove all data-aware control data, set the RowCount property to zero by calling the SetRowCount method.


unboundDS.SetRowCount(0);
See Also