Binding Deep Dive

DependsOn

Gum's ViewModel supports using the DependsOn attribute to define dependencies between properties. By using this attribute, changes in one property can result in changes to other properties. The same property can be used as a dependency for multiple properties, allowing changes to one property resulting in many pieces of UI being updated.

The following code shows how a single variable can be used to update multiple UI properties. First we can declare a ViewModel using DependsOn to make IsBrokeTextVisible and MoneyDisplay depend on Money.

class PlayerViewModel : ViewModel
{
    public int Money
    {
        get => Get<int>();
        set => Set(value);
    }

    [DependsOn(nameof(Money))]
    public bool IsBrokeTextVisible => Money <= 0;

    [DependsOn(nameof(Money))]
    public string MoneyDisplay => $"${Money:N0}";
}

We can use the PlayerViewModel to update the UI in response to Money changing. The following block of code shows how to do so in a code-only project.

var viewModel = new PlayerViewModel();

var mainPanel = new StackPanel();
mainPanel.AddToRoot();
mainPanel.BindingContext = viewModel;

var addMoneyButton = new Button();
mainPanel.AddChild(addMoneyButton);
addMoneyButton.Text = "+";
addMoneyButton.Click += (_, _) =>
    viewModel.Money += 100;

var subtractMoneyButton = new Button();
mainPanel.AddChild(subtractMoneyButton);
subtractMoneyButton.Text = "-";
subtractMoneyButton.Click += (_, _) =>
    viewModel.Money -= 100;

var moneyLabel = new Label();
mainPanel.AddChild(moneyLabel);
moneyLabel.SetBinding(
    nameof(moneyLabel.Text),
    nameof(viewModel.MoneyDisplay));

var isBrokeLabel = new Label();
mainPanel.AddChild(isBrokeLabel);
isBrokeLabel.Text = "No more money!";
isBrokeLabel.SetBinding(
    nameof(isBrokeLabel.IsVisible),
    nameof(viewModel.IsBrokeTextVisible));

If this code were in a Screen defined in Gum with code generation, the code might look like the following block:

Two buttons updating money

Binding Visual Properties

Visual properties can be directly bound. These can be directly bound to properties on a ViewModel, or they can be bound through custom properties on the Forms control. This section discusses the multiple ways that binding can be performed on visuals.

Binding Visual Properties Directly

Visual properties can be bound directly. If the property is not specific to a type of Visual, then the Visual can be directly bound without being casted. For example, the following code shows how to bind the width of a Button to a ButtonWidth property on a ViewModel.

If the property requires a specific type, then the Visual can be casted to access type-specific properties, as shown in the following code block:

Binding Converter Properties (Code Generation)

If your project uses the Gum tool and code generation, then each component and screen has a custom code file which can contain converter properties that can be bound. This allows ViewModels to avoid adding view-specific properties.

For example, consider a screen named GameScreenHud which contains a single label named HealthLabel.

The ViewModel may contain general properties such as CurrentHealth and IsLowHealth, but the view will process these to display the health with a prefix, and to modify the Label property.

The following code could be added to GameScreenHud.cs, which is the custom code file created when the GameScreenHud is generated:

Last updated

Was this helpful?