Exercise - Replace code with .NET MAUI bindings
In this exercise, you'll convert an app that uses events and code-behind to one that uses mostly data binding. The sample app is a weather forecasting app that displays the weather for the day.
Open the starter solution
Clone or download the exercise repo from GitHub.
Note
It is best to clone or download the exercise content to a short folder path, such as C:\dev, to avoid build-generated files exceeding the maximum path length.
Open the WeatherClient.sln solution from the start folder by using Visual Studio or this folder in Visual Studio Code.
Build and run the project to make sure it works. On the screen displayed, you'll see some empty weather details. Press the Refresh button and you'll see the weather details update.
For reference, here's a summary of the classes and files you'll work with in this exercise.
File Description MainPage.xaml Defines the UI and logic for the initial page. The XAML file defines the UI by using markup. MainPage.xaml.cs Defines the UI and logic for the initial page. The associated code-behind file that contains the code related to the UI defined by MainPage.xaml. Services\WeatherService.cs This class simulates a weather reporting service. It contains a single method named GetWeather
that returns aWeatherData
type.Models\WeatherData.cs Contains the weather data. This is a simple record type that provides the day's temperature, precipitation, humidity, wind, and condition. Models\WeatherType.cs An enumeration of the weather condition, sunny or cloudy.
Set the binding context
You'll need to edit the code-behind for the Refresh button's click event handler. The code currently gets the weather data and updates the controls directly. Instead, get the weather data and set it as the binding context for the page.
Open the MainPage.xaml.cs code file.
Review the
btnRefresh_Clicked
method. This method performs the following steps:- Disables the button and enables the "busy" spinner.
- Gets the weather forecast from the weather service.
- Updates the controls on the page with the weather information.
- Enables the button and disables the "busy" spinner.
Remove the code that updates the controls with data. Your event code should look like the following snippet:
private async void btnRefresh_Clicked(object sender, EventArgs e) { btnRefresh.IsEnabled = false; actIsBusy.IsRunning = true; Models.WeatherData weatherData = await Services.WeatherServer.GetWeather(txtPostalCode.Text); btnRefresh.IsEnabled = true; actIsBusy.IsRunning = false; }
Instead of assigning the result of the service's
GetWeather
method to a variable, assign it to theBindingContext
of the page:private async void btnRefresh_Clicked(object sender, EventArgs e) { btnRefresh.IsEnabled = false; actIsBusy.IsRunning = true; BindingContext = await Services.WeatherServer.GetWeather(txtPostalCode.Text); btnRefresh.IsEnabled = true; actIsBusy.IsRunning = false; }
Run the project. Notice that when you press the Refresh button and the weather service returns the data, none of the controls are updated with the weather forecast. You'll fix this bug in the next section.
Create bindings in XAML
Now that the code-behind sets the binding context for the page, you can add the bindings to the controls to use the data on the context.
Open the MainPage.xaml file.
Find the inner
Grid
that contains all theLabel
controls.<Grid Grid.Row="2" RowDefinitions="Auto, Auto, Auto, Auto, Auto" ColumnDefinitions="Auto, Auto" Margin="0,5,0,0"> <Label Grid.Row="0" Grid.Column="0" Text="Condition" VerticalOptions="Center" /> <Image x:Name="imgCondition" Grid.Row="0" Grid.Column="1" HeightRequest="25" WidthRequest="25" Source="question.png" HorizontalOptions="Start" /> <Label Grid.Row="1" Grid.Column="0" Text="Temperature" Margin="0,0,20,0" /> <Label x:Name="lblTemperature" Grid.Row="1" Grid.Column="1" Text="0" /> <Label Grid.Row="2" Grid.Column="0" Text="Humidity" Margin="0,0,20,0" /> <Label x:Name="lblHumidity" Grid.Row="2" Grid.Column="1" Text="0" /> <Label Grid.Row="3" Grid.Column="0" Text="Precipitation" Margin="0,0,20,0" /> <Label x:Name="lblPrecipitation" Grid.Row="3" Grid.Column="1" Text="0" /> <Label Grid.Row="4" Grid.Column="0" Text="Wind" Margin="0,0,20,0" /> <Label x:Name="lblWind" Grid.Row="4" Grid.Column="1" Text="0" /> </Grid>
Add bindings to each of the named
Label
controls. There are four.The
Label.Text
property should have its value changed to the{Binding PROPERTY_NAME}
syntax wherePROPERTY_NAME
is a property from theModels.WeatherData
type defined in Models\WeatherData.cs. Remember, this type is the data type returned by the weather service.For example, the
Label
namedlblWind
(the last label in the grid) should have theText
property look like the following code:<Label x:Name="lblWind" Grid.Row="4" Grid.Column="1" Text="{Binding Wind}" />
Within the
<Grid>
of controls that lists all of the weather details, remove all of thex:Name="..."
attributes.The names aren't required now that the controls aren't referenced in the code-behind.
Verify that your XAML bindings match the following snippet:
<Grid Grid.Row="2" RowDefinitions="Auto, Auto, Auto, Auto, Auto" ColumnDefinitions="Auto, Auto" Margin="0,5,0,0"> <Label Grid.Row="0" Grid.Column="0" Text="Condition" VerticalOptions="Center" /> <Image Grid.Row="0" Grid.Column="1" HeightRequest="25" WidthRequest="25" Source="question.png" HorizontalOptions="Start" /> <Label Grid.Row="1" Grid.Column="0" Text="Temperature" Margin="0,0,20,0" /> <Label Grid.Row="1" Grid.Column="1" Text="{Binding Temperature}" /> <Label Grid.Row="2" Grid.Column="0" Text="Humidity" Margin="0,0,20,0" /> <Label Grid.Row="2" Grid.Column="1" Text="{Binding Humidity}" /> <Label Grid.Row="3" Grid.Column="0" Text="Precipitation" Margin="0,0,20,0" /> <Label Grid.Row="3" Grid.Column="1" Text="{Binding Precipitation}" /> <Label Grid.Row="4" Grid.Column="0" Text="Wind" Margin="0,0,20,0" /> <Label Grid.Row="4" Grid.Column="1" Text="{Binding Wind}" /> </Grid>
Run the app and press the Refresh button. The app works almost like the original.
Notice that the icon representing the Condition doesn't update from the question mark to a sun or cloud icon. Why doesn't the icon change? Because the icon is an image resource that was chosen in code based on the WeatherData.Condition
enumeration value. The enumeration value can't be changed to an image resource without some extra effort This is fixed in the next exercise after you learn more about bindings.