Now that you've learned how to bind an entire table to a DataGrid and bind a table to a ComboBox for viewing one row at a time, the next step is to learn how to use the CurrencyManager. No, this has nothing to do with money. Currency refers to the current state, including the currently active row and mode (editing, adding, etc.) for a specific data source. Windows Forms has built-in support for keeping track of the current state of bound data on your form, and the CurrencyManager object exposes that state information to you. Using the methods and properties of the CurrencyManager object, you can add navigation support to your form.
For this demo, you are again going to use the Customers table in the Northwind database, so create a new Windows Forms application and set up the data objects as you did before. First things first, you need to lay out the controls the way you want to display the details of a single customer. Also, if you're still a little bit confused by what I mean by adding navigation, Figure 5.8 shows controls that will be used to move forward and backward through the data source.
In this example I have used a standard naming convention for all the controls. All controls that you are going to bind to are the same name as the field you are going to bind to it, but with a control prefix in front of it. The prefixes I used are lbl for Labels and txt for TextBoxes. The buttons and label across the bottom are named btnFirst, btnPrevious, lblPosition, btnNext and btnLast, respectively.
Currency Management in Windows Forms is on a perform basis, so you can get a reference to the currency manager object from the form itself through the BindingContext property.
MyBindingManager = _ Me.BindingContext(dsNorthwind, "Customers")
The first parameter is the DataSource you want to get the binding manager for. The second and optional parameter is used if you need to specify a specific DataMember. In this case, you're only going to be dealing with the Customers table inside the dsNorthwind DataSet. This will return the instance of the BindingManagerBase class that you will need to keep track of the currency of the data. The BindingContext property represents the collection of all the BindingManager instances for the current Windows Form, one for each datasource that is data bound on that Form. This collection returns a BindingManagerBase type, but you can cast it into a CurrencyManager object as that is its true underlying type. You will be accessing the CurrencyManager object quite a lot in your code, so it is best to store it as a private form level variable so that you can use it as needed. Listing 5.5 demonstrates obtaining the CurrencyManager object and storing it as a form level variable.
Now that you have cmCustomers to use throughout your code, you need to “link” the controls on the form to the binding manager, so it will know what data to show in what control. For this, you will create a new procedure, as shown in Listing 5.6.
Each control has a DataBindings property, which is a collection of bindings. Each binding is basically a map that links a property of the control to a specific property/field of the data source. So each line in the new SetupControlBindings procedure is setting up a mapping, in this case from the Text property, to whatever field in the table you want. Let's set up the load event for the form to load up the data and set up all of the bindings for the controls. See Listing 5.7.
Now that you have the data and all of the bindings, you need to give the user interface some control over the data. You need to link the buttons to some sort of action to the binding manager, to navigate through the data. The Position property is an integer and can be set to any number from zero to the number of records minus one. Like all arrays and collections in .NET, the Rows collection in the DataTable is zero-based, meaning that the first position is zero, instead of one. The basic idea of using the buttons to navigate is simple. If you want to go to the first record, set the position to zero. If you want to go to the next record, you'll just set the position to one number higher than it is already at and so on. Listing 5.8 shows how to use the cmCustomers variable you set up earlier to change the current position that you will be viewing in the data.
Now that you have the code to navigate through the data source using the currency manager, you need some visual cues to let the user know where they currently are and also make sure the buttons don't allow them to go past the end or beginning of the data source. Again, you'll use the currency manager, as shown in Listing 5.9, to come up with the text for the label as well as to determine whether each button should be enabled or disabled.
You'll notice that the code retrieves the Position and Count properties from the binding manager and stores them in variables. This process saves a bit of typing and it's best to store the properties' values and reuse the values instead of accessing them over and over again. It's quite possible that they might have a bit of logic in them to determine their current state, so you're saving a little processing power, which can't hurt.
The code then sets the lblPosition.Text using String.Format, to more easily concatenate what would be four different pieces. Instead of combining the items using the & operator, you provide a format string using placeholders, and then provide the items to be inserted into those positions. The last four lines simply return a Boolean from an evaluation to make sure that the buttons aren't enabled when they shouldn't be; preventing the position to be changed when it would produce an invalid result.
The procedure looks like an event handler (with sender and EventArgs parameters) because it is going to be hooked up to handle an event raised by the CurrencyManager instance.
You will want this code to execute every time you change position in the data source, because you will need to update the label and button states. Luckily for you, there is an event of the CurrencyManager class called PositionChanged. Visual Basic .NET allows you to easily attach to events at runtime, so you can modify the load event (like in Listing 5.10) so the method will be attached to the PositionChanged event of cmCustomers.
The AddHandler clause will set it up so whenever the PositionChanged event of cmCustomers occurs, the method that you wrote to check button states and show what record you're on will also be called. For more information about dynamic event handlers, take a look at Chapter 3. Alternatively, you could declare the cmCustomers variable with the WithEvents keyword and then add an event handler using the left and right hand side combo boxes in the Visual Studio code editor. This would produce slightly different code, as shown in Listing 5.11.
With all of this code in place, you can now run the application. You'll notice that immediately, there is data populated in the different controls of the form. You can click any of the buttons also and notice that the appropriate record is shown, along with the button's enabled states. The position label is updated accordingly. All of that code you would have needed to write to keep your UI in sync with your data source isn't necessary. You get that all for free, because it's built right into Windows Forms and ready for you to use. You might also notice that the binding manager even takes care of pushing any changed data from the UI back into the data source for you. There are additional methods on CurrencyManager that you might also want to take a look at. The AddNew method adds a new Row to your data source, as well as moves the position to that row. The RemoveAt method is used to remove a row at a specific position.
18.116.87.196