MDI Case Study Purchasing - Part V - ObjectDataSource
MDI Case Study Purchasing - Part V - ObjectDataSource
Introduction
In Part V, we will begin filling our document form, PurchaseOrderForm
. This is a good time to introduce data binding, using the ObjectDataSource
, how it works, and how it can be implemented to easily handle our data bits for us.
ObjectDataSource
ObjectDataSource
will allow us to bind UI elements of our form to properties within the instance of the object it's bound to. For our document form, PurchaseOrderForm
, we are going to use an ObjectDataSource
to bind the UI of the form to our underlying PurchaseOrder
instance. Any changes made to the bound object will be updated in our UI automatically, and changes made by the user will be translated to the underlying PurchaseOrder
automatically. Let's start by defining the ObjectDataSource
for our PurchaseOrder
class. Visual Studio makes data sources very easy, using the Data Sources tool panel. If you don't have the Data Sources tool panel open, you open it from the menu View -> Other Windows -> Data Sources.
Click the "Add Data Source" button, and a dialog will appear. Choose Object, and click Next. In the next step, expand your MDICaseStudyPurchasing
, and expand ObjectBase
, and check PurchaseOrder
, then click Finish. This will add a data source defined by the PurchaseOrder
class.
As you can see in the last screen shot, you now have a data source for PurchaseOrder
in the data sources panel. Properties can be dragged from this panel onto our form to create data bound controls. Let's delete the RichTextBox
from our form, and start filling in our data bound controls. After deleting the RichTextBox
, textBox
, we need to also remove its TextChanged
handler from our code, along with the line that sets its text from our PurchaseOrder
overloaded constructor. From the PurchaseOrderForm(PurchaseOrder purchaseOrder)
constructor, delete the line:
textBox.Text = _purchaseOrder.PurchaseOrderNumber;
And delete the textBox_TextChanged
handler method:
private void textBox_TextChanged(object sender, EventArgs e)
{
this.PurchaseOrder.PurchaseOrderNumber = textBox.Text;
}
Now we are back to a blank form. Let's add a data bound control for the PurchaseOrderNumber
property. The icon beside the property in the data sources panel tells you what type of control dragging it onto the form will create. PurchaseOrderNumber
has already defaulted to TextBox
, which is what we want, but you can change this but clicking the dropdown for the property, and selecting a different control type. What controls are available vary by the property Type. Additional controls can be added to this list by customizing, but that is beyond the scope of this article. Other good articles exist on customizing the list of available controls. So we already have TextBox
assigned to the PurchaseOrderNumber
property, so let's drag it onto our form. A few new things happen. First, a binding source is created and added, which is accessible in the non display items area. Secondly, a binding navigator toolbar is created. Lastly, a label for our property, as well as the control for our property are created. We don't need the binding navigator, so simply select it, and delete it.
Now the default binding type is OnValidation
. This means the data source is only updated after the control passes validation. Since TextBox
doesn't pass validation until after it loses focus, the data source won't update until after the TextBox
loses focus, unless you force it to, which we will need to do. Double click the TextBox
to create an event handler for it's TextChanged
event. In this handler, we will update the data source manually, to be sure the most current user provided data is updated to our data object. To do this, we step through all of the control's bindings, and call the WriteValue()
method for each.
private void purchaseOrderNumberTextBox_TextChanged(object sender, EventArgs e)
{
foreach (Binding b in purchaseOrderNumberTextBox.DataBindings)
{
b.WriteValue();
}
}
Lastly, to connect the final dot, we need to make the underlying PurchaseOrder
instance the data source for the BindingSource
by setting the DataSource
property of the BindingSource
to the underlying PurchaseOrder
instance in the PurchaseOrderForm
constructors. After the InitializeComponent()
call, add the lines:
public PurchaseOrderForm()
{
.....
InitializeComponent();
purchaseOrderBindingSource.DataSource = _purchaseOrder;
purcahseOrderBindingSource.ResetBindings(false);
}
public PurchaseOrderForm(PurchaseOrder purchaseOrder)
{
.....
InitializeComponent();
purchaseOrderBindingSource.DataSource = _purchaseOrder;
purchaseOrderBindingSource.ResetBindings(false);
?}
ResetBindings(false)
will cause all of the controls using this binding source to update their displayed value, rereading the data from the underlying object source. Specifying false
for this tells the BindingSource
that the schema has not changed.
One final bit of touch-up. Anytime the underlying PurchaseOrder changes, we want our BindingSource to update all of our bound controls, so lets go to the purchaseOrder_Changed even handler, and before we "bubble up" the event with OnChanged(e), lets add the line to reset the bindings. Now the event handler should look like
private void purchaseOrder_Changed(object sender, PurchaseOrderChangedEventArgs e)
{
purchaseOrderBindingSource.ResetBindings(false);
OnChanged(e);
}
So now, we are back to where we were, with the Purchase Order Number being saved. You can test out the Application again, and see that it once again functions, but now we are using the ObjectDataSource
to handle our data object. That does it for Part V. Next, we will continue toward the final look for out PurchaseOrderForm
.
Points of Interest
ObjectDataSource