The BindingContext property is used for all data binding. This tutorial introduces the BindingContext property and creates a simple example using BindingContext to control the UI.
For this tutorial we will create a Gum screen which contains the following:
Points Display
Health Bar
Button for awarding points
Button for taking damage
Button for healing
Normally the actions performed by the buttons listed above would occur through regular game logic (such as collision) but we will use buttons for the sake of simplicity. The specifics of the visuals do not matter, so your screen may look like the following:
A few details in the screen above are important:
The three buttons are FlatRedBall.Forms Button objects. In other words, the three buttons are created in Gum using components which implement the Button behavior. The most common of these is ButtonStandard.
The HealthBar (ColoredRectangle) is contained within a HealthContainer (Container) using the Percent Width Units
Each object in the screen is descriptively named. This will make data binding easier.
The screen is called GameScreenGum. This is the default Gum Screen name for a FlatRedBall Screen called GameScreen. If you have created a game with a GameScreen using the wizard, you will also have a GameScreenGum
The first step in binding to your UI is to create a ViewModel object. ViewModel objects contain all of the properties which you would want to control on your UI programmatically. For the screen above, we will control the following properties:
The string displayed by the PointsTextInstance
The string displayed by the HealthTextInstance
The width of the HealthBar
The ViewModel class should implement the INotifyPropertyChanged interface. Fortunately, FlatRedBall provides a convenient class for this. View models are plain C# classes that are created in Visual Studio. We recommend creating a ViewModels folder in your project, but you can organize them however you like. The following code is an example of what the ViewModel class might look like:
The base ViewModel class provides common functionality for MVVM implementation - specifically the Get and Set functions and the DependsOn attribute. Using the ViewModel base class is not required, and any INotifyPropertyChanged implementation will work.
The Get and Set functions provide a quick way to implement notification to the UI. When the Set function is called (such as when Score is assigned), internally the Score value will be stored, and any object watching for changes to the Score variable will be notified. Furthermore, any object watching properties which depend on Score will also be notified.
The DependsOn attribute creates a dependency relationship between the property which has the attribute (such as ScoreDisplay) and the property which it depends on (such as Score). Once this dependency is established, changing the Score property will also notify the UI that ScoreDisplay has changed. Notice that a single property can depend on multiple properties, as is the case of HealthDisplay depending on both CurrentHealth and MaxHealth.
The ViewModel establishes which properties can be assigned, and the dependency between properties. Once a ViewModel is created, it can be applied to a Gum object. Note that ViewModels can be applied to Gum objects (GraphicalUiElements) or Forms objects (such as Button). BindingContext assignments cascade - you only need to assign the BindingContext at the top level and all children will recursively receive the same BindingContext.
Typically the BindingContext is done at the root level. We recommend assigning the Forms object which is available if you are using Forms in your game. Once the BindingContext is assigned, each individual UI property needs to be bound to the corresponding ViewModel property. The following code shows how this type of binding would be done:
Note that the above code assigns the binding on Gum objects through GumScreen. Although we're not doing it in this tutorial, we could also call SetBinding on Forms objects. For example, if the ViewModel had a property which was to be used as the Text on one of the buttons, the following code could be used:
This topic is covered in more detail in the next tutorial.
The ViewModel object is defined at GameScreen class scope. This is required so that the game can make modifications to the ViewModel after the screen is initialized. FlatRedBall recommends that the ViewModel property is named ViewModel to standardize code across different pages and views.
Once the ViewModel is created, we assign the BindingContext. This assignment tells the GumScreen and everything inside of the GumScreen to use this as its BindingContext. This assignment will also assign the BindingContext on any Forms objects in your screen, so you only need to do this assignment on the GumScreen. Once the BindingContext is assigned, the code establishes individual bindings between UI properties and ViewModel properties. This binding creates an automatic connection between the ViewModel property to the UI property, so that any changes to the ViewModel will automatically update the UI (assuming the Get and Set functions and DependsOn are written correctly in the ViewModel). Notice that the code uses the nameof keyword in C#. The code above could also be written as shown in the following snippet:
While this is less verbose, it produces code which is easier to break. Using nameof provides compile-time checks against referenced properties.
Once the binding is set up, assigning properties on the ViewModel will automatically update the UI. For example, the values above initialize the score and health as shown in the following screenshot:
The ViewModel properties can be updated at any time. Doing so automatically updates the bound UI. For example, the following code can be used to modify the properties in response to button clicks:
Notice that the click events on the buttons do not directly access any UI elements - only the properties on the ViewModel. This makes it much easier to maintain the UI and to continue to add dependencies.