> For the complete documentation index, see [llms.txt](https://docs.flatredball.com/gum/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flatredball.com/gum/code/binding-viewmodels/items-binding-listbox-combobox-itemscontrol.md).

# Items Binding (ListBox, ComboBox, ItemsControl)

## Introduction

Some controls support the dynamic creation of children when their Items property is bound. These include `ListBox`, `ComboBox`, and `ItemsControl`. This page discusses how to dynamically create these items using the Items property.

## Items Binding Concepts

Controls which have an Items property automatically create children when an object is added to the Items property. Adding items can be explicitly performed by calling `Items.Add` or can be performed by binding to an observable collection and changing that collection.

Although binding can be performed to any collection, `ObservableCollection` is commonly used so that the collection can change dynamically, automatically updating the displayed controls. All operations on `ObservableCollection` are supported including adding, removing, clearing, and reordering.

Binding can be performed to any type which implements `INotifyCollectionChanged`, so developers familiar with MVVM can use any view model implementation. This document uses Gum's `ViewModel` for simplicity.

## ItemsControl Binding

`ItemsControl` is similar to `ListBox`, but it does not have any restrictions on visual types since `ItemControl` does not support the concept of selection. This makes `ItemsControl` suitable for general usage.

The following code shows how to bind an `ItemsControl` to a `ViewModel`'s `ObservableCollection`:

```csharp
public class ExampleViewModel : ViewModel
{
    public ObservableCollection<DateTime> Dates
    {
        get;
        private set;
    } = new ObservableCollection<DateTime>();
}

//------------------------------------------
// Initialize
var viewModel = new ExampleViewModel();

var stackPanel = new StackPanel();
stackPanel.AddToRoot();
stackPanel.Anchor(Anchor.Center);

var itemsControl = new ItemsControl();
stackPanel.AddChild(itemsControl);
itemsControl.Width = 200;
itemsControl.BindingContext = viewModel;
itemsControl.SetBinding(
    nameof(itemsControl.Items),
    nameof(viewModel.Dates));

var addButton = new Button();
stackPanel.AddChild(addButton);
addButton.Text = "Add Date";
addButton.Click += (_, _) =>
{
    viewModel.Dates.Add(System.DateTime.Now);
};
```

[Try on XnaFiddle.NET](https://xnafiddle.net/#code=H4sIAAAAAAAACo1UwY7aMBC95yusPSXqytq2t1JWKtBFHOhWhaW9rUwygIuxke2EbVf8e8dOMCYLor7Ennkz8-bZk9JwuSRjJdWQbWBYbjpJ6U24pQ9Kb8wbA-0rabUSZzwDWLBS2Bk3JROGzj7GkHFVnWT_yTUsNFY9GMc818qohaW_JKMPzrVTen3FTYeabVc8D3Qmf4yFUKk-IWchILdcSUMf579xO1YFiE6SbMu54DnJBTOGfH1hm62AGYed95NPJOyT14TgavCPcwO6YnMBx9SfB8zClG_gnrid8fg6yq0l2E44bDWvEEPMwbgnXSJhdyVxmnWSfYu0u7n3yNR9G5IHTQZQ8RzGTLIlaLIMSnlMuZlgJfS77dOIdO8j2-EuUaGoa18qzchryNWwPlswtStusg4ZmbEqDapqOLaFEVaX0CHYR62EstgmFERVoDUvgFSKF2QkueVM8L-QZi0lPV8aAVyhW3L6_GagDWqHrxA1C6EV06QK11uTb9962g4wluXr70yGiEkwOOwBeoTRL0UxVT-Uspf8Ml8pnZ7MQWOkfZAWdJsDx2dsmtFrWIwi02Ue_RUXRRqHR9DYjEwKu8LcH-7uLiB6XBY4Ve4ILxahQcoLAROwTUwaAG5J7FctTlhR3052ew4XylA_WFlbHFYUvdJaJRtl6sM1TUJUhAs2Oq07vEG4H-ebc6A-TsWavOuS9PmWPGc4QwF0fK6e5WkHjkR6mGr6Te0iCvuouTkzED_0BnZldJ62BaZO3bS6_GTZbM7PUYMOoCMTX_28-wqDgWa7_6h_8tdAMYHpFH97bgiUlguhdqB7oow51Zx9_jZTb3zDc5_8A76UCUnlBgAA)

<figure><img src="/files/fN7gNyBHSufDT7AvXkqk" alt=""><figcaption><p>Items added through binding</p></figcaption></figure>

The `FrameworkElementTemplate` template can be modified to support creating custom FrameworkElement types as shown in the following code block:

<pre class="language-csharp"><code class="lang-csharp">public class ExampleViewModel : ViewModel
{
    public ObservableCollection&#x3C;DateTime> Dates
    {
        get;
        private set;
    } = new ObservableCollection&#x3C;DateTime>();
}

//------------------------------------------
// Initialize
var viewModel = new ExampleViewModel();

var stackPanel = new StackPanel();
stackPanel.AddToRoot();
stackPanel.Anchor(Anchor.Center);

var itemsControl = new ItemsControl();
stackPanel.AddChild(itemsControl);
itemsControl.Width = 200;
itemsControl.BindingContext = viewModel;
itemsControl.SetBinding(
    nameof(itemsControl.Items),
    nameof(viewModel.Dates));

<strong>itemsControl.FrameworkElementTemplate = 
</strong><strong>    new Gum.Forms.FrameworkElementTemplate(typeof(Button));
</strong>
var addButton = new Button();
stackPanel.AddChild(addButton);
addButton.Text = "Add Date";
addButton.Click += (_, _) =>
{
    viewModel.Dates.Add(DateTime.Now);
};

</code></pre>

<figure><img src="/files/Q58X0HknWA5lGbZNQnF3" alt=""><figcaption></figcaption></figure>

Each item created through the `FrameworkElementTemplate` is bound to a corresponding item in the Items collection. This means that each `FrameworkElement` can be further customized through its own binding.

For example, we can create a top-level view model which contains a collection of weapons. Each weapon is displayed with a custom button.

The following code shows the two view models:

```csharp
// This is the top-level ViewModel for the example.
public class TopLevelViewModel : ViewModel
{
    public ObservableCollection<WeaponViewModel> Weapons
    {
        get;
        private set;
    } = new ObservableCollection<WeaponViewModel>();
}

// This is the view model representing a single weapon.
// Each instance of WeaponViewModel results in an item
// added to the ItemsControl.
public class WeaponViewModel : ViewModel
{
    public string WeaponName
    {
        get => Get<string>();
        set => Set(value);
    }
    public string WeaponDetails
    {
        get => Get<string>();
        set => Set(value);
    }
}
```

Each `WeaponViewModel` instance is displayed with a new Button instance called `ButtonWithSubtext` as shown in the following code block:

```csharp
// A special button which includes text and subtext
public class ButtonWithSubtext : Button
{
    public ButtonWithSubtext()
    {
        // Existing properties can be bound...
        this.SetBinding(
            nameof(this.Text),
            nameof(WeaponViewModel.WeaponName));

        Visual.Dock(Gum.Wireframe.Dock.FillHorizontally);

        var mainText = ((ButtonVisual)Visual).TextInstance;
        mainText.Dock(Gum.Wireframe.Dock.Top);

        // ... or new visuals with their own bound properties
        // can also be added
        var subText = new TextRuntime();
        subText.Color = new Color(220,220,200);
        this.AddChild(subText);
        subText.Dock(Gum.Wireframe.Dock.Top);
        subText.Y = 20;
        subText.SetBinding(
            nameof(subText.Text),
            nameof(WeaponViewModel.WeaponDetails));
    }
}
```

Finally, these view models and custom button can be used to display weapons in an `ItemsControl` as shown in the following code block:

```csharp
// Initialize
var viewModel = new TopLevelViewModel();

var stackPanel = new StackPanel();
stackPanel.AddToRoot();
stackPanel.Anchor(Anchor.Center);

itemsControl = new ItemsControl();
stackPanel.AddChild(itemsControl);
//itemsControl.Height = 70;
itemsControl.Width = 250;
itemsControl.BindingContext = viewModel;
itemsControl.SetBinding(
    nameof(itemsControl.Items),
    nameof(viewModel.Weapons));

itemsControl.FrameworkElementTemplate = 
    new Gum.Forms.FrameworkElementTemplate(typeof(ButtonWithSubtext));


viewModel.Weapons.Add(new WeaponViewModel
{
    WeaponName = "Sword",
    WeaponDetails = "A sharp blade used for cutting."
});

viewModel.Weapons.Add(new WeaponViewModel
{
    WeaponName = "Bow",
    WeaponDetails = "A ranged weapon that shoots arrows."
});

viewModel.Weapons.Add(new WeaponViewModel
{
    WeaponName = "Staff",
    WeaponDetails = "A magical staff used for casting spells."
});

viewModel.Weapons.Add(new WeaponViewModel
{
    WeaponName = "Dagger",
    WeaponDetails = "A small, sharp blade used for stabbing."
});
```

<figure><img src="/files/s8xpw1bpjYzlNLlJiohl" alt=""><figcaption><p>ItemsControl displaying weapons using a customized Button</p></figcaption></figure>

## Code Example: Binding Combo Box Items

The following example shows how to bind a ComboBox to a ViewModel which contains a list of weapons.

```csharp
using Gum.Forms;
using Gum.Forms.Controls;
using Gum.Forms.DefaultVisuals.V3;
using Gum.Mvvm;
using Gum.Wireframe;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Gum;
using Gum.GueDeriving;
using System.Collections.ObjectModel;

namespace MonoGameAndGum;

// This is the top-level ViewModel for the example.
public class TopLevelViewModel : ViewModel
{
    public ObservableCollection<WeaponViewModel> Weapons
    {
        get;
        private set;
    } = new ObservableCollection<WeaponViewModel>();
}

// This is the view model representing a single weapon.
// Each instance of WeaponViewModel results in an item
// added to the ItemsControl.
public class WeaponViewModel : ViewModel
{
    public string WeaponName
    {
        get => Get<string>();
        set => Set(value);
    }
    public string WeaponDetails
    {
        get => Get<string>();
        set => Set(value);
    }
}

// A special button which includes text and subtext
public class WeaponDisplay : ListBoxItem
{
    TextRuntime subText;

    public WeaponDisplay() : base()
    {
        Visual.Height = 10;

        var text = ((ListBoxItemVisual)this.Visual).TextInstance;
        text.Anchor(Gum.Wireframe.Anchor.TopLeft);

        // add a 2nd Text instance under the main text:
        subText = new TextRuntime();
        subText.Y = 22;
        subText.Color = new Color(220, 220, 200);
        subText.WidthUnits = Gum.DataTypes.DimensionUnitType.RelativeToParent;

        this.AddChild(subText);
    }

    public override void UpdateToObject(object o)
    {
        var asWeaponViewModel = o as WeaponViewModel;

        if(asWeaponViewModel != null)
        {
            coreText.RawText = asWeaponViewModel.WeaponName;
            subText.Text = asWeaponViewModel.WeaponDetails;
        }
    }
}



public class Game1 : Game
{
    private GraphicsDeviceManager _graphics;
    GumService GumUI => GumService.Default;
    public Game1()
    {
        _graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        IsMouseVisible = true;
    }

    protected override void Initialize()
    {
        GumUI.Initialize(this);

        var viewModel = new TopLevelViewModel();

        var comboBox = new ComboBox();
        comboBox.AddToRoot();
        comboBox.Anchor(Anchor.Center);
        comboBox.Width = 300;
        comboBox.BindingContext = viewModel;
        comboBox.SetBinding(
            nameof(comboBox.Items),
            nameof(viewModel.Weapons));
        comboBox.DisplayMemberPath = nameof(WeaponViewModel.WeaponName);

        comboBox.FrameworkElementTemplate =
            new Gum.Forms.FrameworkElementTemplate(typeof(WeaponDisplay));


        viewModel.Weapons.Add(new WeaponViewModel
        {
            WeaponName = "Sword",
            WeaponDetails = "A sharp blade used for cutting."
        });

        viewModel.Weapons.Add(new WeaponViewModel
        {
            WeaponName = "Bow",
            WeaponDetails = "A ranged weapon that shoots arrows."
        });

        viewModel.Weapons.Add(new WeaponViewModel
        {
            WeaponName = "Staff",
            WeaponDetails = "A magical staff used for casting spells."
        });

        viewModel.Weapons.Add(new WeaponViewModel
        {
            WeaponName = "Dagger",
            WeaponDetails = "A small, sharp blade used for stabbing."
        });

        base.Initialize();
    }

    protected override void Update(GameTime gameTime)
    {
        GumUI.Update(gameTime);

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        GumUI.Draw();

        base.Draw(gameTime);
    }
}

```

<figure><img src="/files/rIblgALLxRkeT4pr0a2V" alt=""><figcaption><p>ComboBox with custom ListBoxItems and binding</p></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flatredball.com/gum/code/binding-viewmodels/items-binding-listbox-combobox-itemscontrol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
