LogoLogo
  • Gum Tool
    • Introduction
    • Setup
      • Running from Source
    • Showcase
    • Tutorials and Examples
      • Intro Tutorials
        • 1 - The Basics
        • 2 - Variables Tab
        • 3 - Files
        • 4 - Components
        • 5 - Exposing Variables
        • 6 - Parent
        • 7 - States
        • 8 - State Categories
      • Animation Tutorials
        • 1 - Introduction to Animation
        • 2 - Creating an Animation
        • 3 - Playing Animations inside other Animations
        • 4 - Combining Multiple Categories
      • Examples
        • Bottom-Up Stack
        • Centering
        • Custom NineSlice
        • Health Bar
        • Padding
    • Gum Elements
      • General Properties
        • Alpha
        • Base Type (Inheritance)
        • Blend
        • Clips Children
        • Has Events
        • Height Units
        • Ignored By Parent Size
        • Locked
        • Max Height
        • Max Width
        • Min Height
        • Min Width
        • Order
        • Parent
        • Rotation
        • Visible
        • Variable References
        • Width Units
        • X
        • X Origin
        • X Units
        • Y
        • Y Origin
        • Y Units
      • Behaviors
        • Default Implementation
      • Circle
      • ColoredRectangle
      • Component
        • Default Child Container
      • Container
        • Children Layout
        • Contained Type
        • Is Render Target
        • Stack Spacing
        • Wraps Children
      • NineSlice
        • Blend
        • Custom Frame Texture Coordinate Width
        • Texture Address
        • Texture Left
        • Texture Top
      • Polygon
        • Points
      • Skia Standard Elements
        • General Properties
          • Has Dropshadow
          • Is Filled
          • Use Gradient
        • Arc
          • Start Angle
          • Sweep Angle
          • Thickness
        • Canvas
        • ColoredCircle
        • LottieAnimation
        • RoundedRectangle
          • Corner Radius
        • Svg
      • Sprite
        • Color
        • Source File
        • Texture Address
        • Wrap
      • States
        • Categories
      • Text
        • Blue
        • Color
        • Font
        • Font Scale
        • Font Size
        • Green
        • Is Bold
        • Is Italic
        • MaxLettersToShow
        • Outline Thickness
        • Red
        • Text
        • Text Overflow Horizontal Mode
        • Text Overflow Vertical Mode
        • Use Custom Font
        • Use Font Smoothing
    • Project Tab
    • Code Tab
      • Runtime Generation Details
      • Generation Scope
      • Inheritance Location
      • Is CodeGen Plugin Enabled
      • Show CodeGen Preview
    • Localization
    • Menu
      • Content
      • Project Properties
    • Plugins
      • AddAndRemoveVariablesForType
      • AddMenuItem
      • Export
      • Setting Up Post Build Events
    • Variables
      • Add Variable
    • Bitmap font generator (.fnt)
    • Upgrading
      • Migrating 2025 April 27 to Preview
      • Breaking Changes
        • Removal of Variable Spaces
  • Code
    • Gum Code Reference
      • AnimationRuntime
      • BitmapCharacterInfo
      • BitmapFont
      • Camera
      • CircleRuntime
      • ColoredRectangleRuntime
      • Component Runtimes
      • ContainerRuntime
      • Cursor
      • Gum Class Overview
      • DataUiGrid
        • Reflection
        • Categories
      • ElementSave
        • ToGraphicalUiElement
      • GraphicalUiElement
        • Absolute Values
        • AddToManagers
        • AnimateSelf
        • ApplyState
        • BlendState
        • CanvasHeight
        • CanvasWidth
        • Children
        • ContainedElements
        • Font Values
        • GetAbsoluteHeight
        • GetAbsoluteWidth
        • GetChildByNameRecursively
        • GetFrameworkElementByName
        • IsAllLayoutSuspended
        • Parent
        • RemoveFromManagers
        • UpdateLayout
      • GumProjectSave
      • IDataUi
      • InstanceMember
      • InstanceSave
      • InteractiveGue
        • CurrentInputReceiver
        • RaiseChildrenEventsOutsideOfBounds
        • RollOverBubbling
      • IPositionedSizedObject
      • Layer
      • NineSliceRuntime
      • RectangleRuntime
      • Renderer
        • SinglePixelTexture
      • SelectedState
      • SpriteRenderer
        • LastFrameDrawStates
      • SpriteRuntime
        • TextureAddress
        • TextureHeight
        • TextureLeft
        • TextureTop
        • TextureWidth
      • TextRuntime
        • Color
        • FontScale
        • FontSize
        • HorizontalAlignment
        • Text Wrapping
        • VerticalAlignment
      • VariableSave
    • FNA
    • Kni
    • Meadow
    • MonoGame
      • Setup
        • Linking Game Project to Source (Optional)
      • Tutorials
        • Gum Project Forms Tutorial
          • Setup
          • Gum Screens
          • Common Component Types
          • Styling
          • Multiple Screens
        • Code-Only Gum Forms Tutorial
          • Setup
          • Forms Controls
          • ListBox Items
          • Input in Forms
        • [Deprecated] Gum Project (.gumx) Tutorial
          • Setup
          • Gum Screens
          • Gum Forms
          • Customizing Forms
          • Strongly Typed Components Using Code Generation
          • Multiple Screens
      • Setup for GumBatch (Optional)
      • Loading a Gum Project (Optional)
      • async Programming
      • Custom Runtimes
      • GumBatch
      • Gum Forms
        • Binding (ViewModels)
        • Controls
          • Button
          • CheckBox
          • FrameworkElement
            • BindingContext
            • IsEnabled
            • IsFocused
            • ModalRoot and PopupRoot
            • SetBinding
          • ListBox
          • ListBoxItem
          • MenuItem
          • PasswordBox
          • RadioButton
          • ScrollViewer
            • VerticalScrollBarValue
          • StackPanel
          • Slider
          • TextBox
        • Control Customization In Code
          • MenuItem
        • Control Customization in Gum Tool
        • Gamepad Support
        • Keyboard Support
        • Troubleshooting
      • File Loading
      • Resizing the Game Window
      • Known Issues
      • Samples
        • MonoGameGumFormsSample
    • Nez
    • Silk.NET
    • SkiaGum
      • Setup
        • WPF
    • .NET MAUI
      • Setup
Powered by GitBook
On this page
  • Introduction
  • Default ToString Implementation
  • DisplayMemberPath
  • FrameworkElementTemplate
  • Customizing ComboBox Text
  • SelectedObject
  • Conclusion

Was this helpful?

Edit on GitHub
Export as PDF
  1. Code
  2. MonoGame
  3. Tutorials
  4. Code-Only Gum Forms Tutorial

ListBox Items

PreviousForms ControlsNextInput in Forms

Last updated 1 month ago

Was this helpful?

Introduction

ListBoxes are one of the more complex controls in Gum Forms. This document discusses how to work with and customize ListBox items.

This document uses the ListBox control for consistency but most of the same code applies to ComboBox. This document mentions where ComboBox differs from ListBox.

Default ToString Implementation

By default whenever an instance is added to the ListBox Items property, the ListBox creates a ListBoxItem internally to display the object. Notice that the following code adds integers to a ListBox's Items property which internally creates UI elements to represent the integers.

var listBox = new ListBox();
for (int i = 0; i < 10; i++)
{
    listBox.Items.Add(i);
}
mainPanel.AddChild(listBox);

The following code produces similar results, although explicitly creating ListBoxItems is less common:

var listBox = new ListBox();
for (int i = 0; i < 10; i++)
{
    var listBoxItem = new ListBoxItem();
    listBoxItem.UpdateToObject(i);
    listBox.Items.Add(listBoxItem);
}
mainPanel.AddChild(listBox);

The following code produces similar results, although explicitly creating ListBoxItems is less common:

var listBox = new ListBox();
for (int i = 0; i < 10; i++)
{
+   var listBoxItem = new ListBoxItem();
+   listBoxItem.UpdateToObject(i);
+   listBox.Items.Add(listBoxItem);
}
mainPanel.AddChild(listBox);

By default the ListBoxItem displays the ToString of whatever is added to the Items property. In the case of integers, the string representation of the integer is displayed. However, if we display an object, such as information about a weapon, the default display is not very useful.

For example, consider the following code:

//Define WeaponDefinition
class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
}

// Later, create the ListBox:
var listBox = new ListBox();
listBox.Width = 400;
listBox.Items.Add(new WeaponDefinition
{
    Name = "Dagger",
    DamageDealt = 5,
    RequiredLevel = 1,
    Price = 10
});
listBox.Items.Add(new WeaponDefinition
{
    Name = "Sword",
    DamageDealt = 10,
    RequiredLevel = 2,
    Price = 20
});
listBox.Items.Add(new WeaponDefinition
{
    Name = "Axe",
    DamageDealt = 15,
    RequiredLevel = 3,
    Price = 30
});
mainPanel.AddChild(listBox);

In this case ToString is called on WeaponDefinition, but this doesn't provide useful information to the user:

We can change the displayed string by modifying the ToString method in WeaponDefinition.

class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
    public override string ToString() => 
        $"{Name} {DamageDealt}dmg requires lvl{RequiredLevel}";
}
class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
+   public override string ToString() => 
+       $"{Name} {DamageDealt}dmg requires lvl{RequiredLevel}";
}

By implementing a custom ToString method on the WeaponDefinition class we can customize how it is displayed in the ListBox. While this is handy, it does limit us because we may want to modify ToString for other purposes such as customizing information in the debugger.

DisplayMemberPath

DisplayMemberPath can be used to change which property is used to display each item. If this value is its default value of an empty string, then the ToString method is used. If this value is assigned, then it must be the name of a property on the source item. This property has the benefit of not relying on ToString which might be used for debugging or might change for other reasons in the future.

For example, the following code shows how to display the weapon's name:

//Define WeaponDefinition
class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
}

// Later, create the ListBox:
var listBox = new ListBox();
listBox.Width = 400;
listBox.Items.Add(new WeaponDefinition
{
    Name = "Dagger",
    DamageDealt = 5,
    RequiredLevel = 1,
    Price = 10
});
listBox.Items.Add(new WeaponDefinition
{
    Name = "Sword",
    DamageDealt = 10,
    RequiredLevel = 2,
    Price = 20
});
listBox.Items.Add(new WeaponDefinition
{
    Name = "Axe",
    DamageDealt = 15,
    RequiredLevel = 3,
    Price = 30
});
listBox.DisplayMemberPath = nameof(WeaponDefinition.Name);
mainPanel.AddChild(listBox);
//Define WeaponDefinition
class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
}

// Later, create the ListBox:
var listBox = new ListBox();
listBox.Width = 400;
listBox.Items.Add(new WeaponDefinition
{
    Name = "Dagger",
    DamageDealt = 5,
    RequiredLevel = 1,
    Price = 10
});
listBox.Items.Add(new WeaponDefinition
{
    Name = "Sword",
    DamageDealt = 10,
    RequiredLevel = 2,
    Price = 20
});
listBox.Items.Add(new WeaponDefinition
{
    Name = "Axe",
    DamageDealt = 15,
    RequiredLevel = 3,
    Price = 30
});
+listBox.DisplayMemberPath = nameof(WeaponDefinition.Name);
mainPanel.AddChild(listBox);

Although this approach is more flexible than using ToString, it does not provide the full benefits of running code on each item to customize its appearance. The next section shows how to create derived forms classes to customize their UpdateToObject method.

FrameworkElementTemplate

We can customize the way WeaponDefinition is displayed without making any changes to WeaponDefinition itself. Instead we can create a new class that is responsible for converting a WeaponDefinition instance into a string to be displayed by each ListBoxItem.

To do this, we need to perform the following steps:

  1. Create a new class that inherits from ListBoxItem. The purpose of this class is to convert our WeaponDefinition into a string.

  2. Associate this class with our ListBox by assigning the ListBox's FrameworkElementTemplate property

The following code has been modified to create and use a WeaponDefinitionListBoxItem:

class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
}

public class WeaponDefinitionListBoxItem : ListBoxItem
{
    public override void UpdateToObject(object objectInstance)
    {
        if(objectInstance is WeaponDefinition definition)
        {
            var textToDisplay =
                $"{definition.Name} {definition.DamageDealt}dmg requires lvl{definition.RequiredLevel}";
            base.UpdateToObject(textToDisplay);
        }
        else
        {
            base.UpdateToObject($"Error updating to {objectInstance}");
        }
    }
}

// Later, create the ListBox
var listBox = new ListBox();
listBox.FrameworkElementTemplate =
    new FrameworkElementTemplate(typeof(WeaponDefinitionListBoxItem));
//...
class WeaponDefinition
{
    public string Name { get; set; }
    public int DamageDealt { get; set; }
    public int RequiredLevel { get; set; }
    public int Price { get; set; }
-   public override string ToString() => 
-       $"{Name} {DamageDealt}dmg requires lvl{RequiredLevel}";
}

+public class WeaponDefinitionListBoxItem : ListBoxItem
+{
+    public override void UpdateToObject(object objectInstance)
+    {
+        if(objectInstance is WeaponDefinition definition)
+        {
+            var textToDisplay =
+                $"{definition.Name} {definition.DamageDealt}dmg requires lvl{definition.RequiredLevel}";
+            base.UpdateToObject(textToDisplay);
+        }
+        else
+        {
+            base.UpdateToObject($"Error updating to {objectInstance}");
+        }
+    }
+}

// Later, create the ListBox
var listBox = new ListBox();
+listBox.FrameworkElementTemplate =
+    new FrameworkElementTemplate(typeof(WeaponDefinitionListBoxItem));
//...

This code example creates a ListBoxItem named WeaponDefinitionListBoxItem. As the name suggests, it is specifically created to display WeaponDefinition instances. Of course, you could create a more generalized version of this class which might handle a variety of different types of items.

Customizing ComboBox Text

As mentioned above, the ComboBox control is similar to ListBox. For example, we can change the type from ListBox to ComboBox to get nearly identical behavior as shown in the following code block:

var comboBox = new ComboBox();
comboBox.FrameworkElementTemplate =
    new FrameworkElementTemplate(typeof(WeaponDefinitionListBoxItem));
comboBox.Width = 400;
comboBox.Items.Add(new WeaponDefinition
{
    Name = "Dagger",
    DamageDealt = 5,
    RequiredLevel = 1,
    Price = 10
});
comboBox.Items.Add(new WeaponDefinition
{
    Name = "Sword",
    DamageDealt = 10,
    RequiredLevel = 2,
    Price = 20
});
comboBox.Items.Add(new WeaponDefinition
{
    Name = "Axe",
    DamageDealt = 15,
    RequiredLevel = 3,
    Price = 30
});
mainPanel.AddChild(comboBox);

This code compiles and works mostly the way we want it, but not perfectly. Notice that WeaponDefinition's ToString is still called to display the main text on the combo box.

Fortunately we can create a class that is derived from ComboBox which overrides the UpdateToObject method just like we did earlier for ListBoxItem.

public class WeaponDefinitionComboBox : ComboBox
{
    public override void UpdateToObject(object objectInstance)
    {
        if (objectInstance is WeaponDefinition definition)
        {
            var textToDisplay =
                $"{definition.Name} {definition.DamageDealt}dmg requires lvl{definition.RequiredLevel}";
            base.UpdateToObject(textToDisplay);
        }
        else
        {
            base.UpdateToObject($"Error updating to {objectInstance}");
        }
    }
}

Now we can use this new ComboBox-deriving class:

var comboBox = new WeaponDefinitionComboBox();
comboBox.FrameworkElementTemplate =
    new FrameworkElementTemplate(typeof(WeaponDefinitionListBoxItem));
// ...
-var comboBox = new ComboBox();
+var comboBox = new WeaponDefinitionComboBox();
comboBox.FrameworkElementTemplate =
    new FrameworkElementTemplate(typeof(WeaponDefinitionListBoxItem));
// ...

SelectedObject

Once items are added to a ListBox, the selection can be accessed through the SelectedObject property. For example, we could handle equipping the selected weapon using code similar to the following block:

var equipButton = new Button();
equipButton.Click += (_, _) =>
{
    var weapon = listBox.SelectedObject as WeaponDefinition;
    if(weapon != null)
    {
        EquipWeapon(weapon);
    }
};
mainPanel.AddChild(equipButton);

Keep in mind that the ListBoxItem is responsible for converting what was added to the ListBox Items property into a string, but the Items and SelectedObject property are still referencing the WeaponDefinition instances.

Conclusion

This document shows how to work with ListBox and ComboBox Items. A future tutorial discusses how to further customize the appearance of ListBoxItems.

The next tutorial covers how to use various input hardware including the mouse, keyboard, and gamepad with Gum UI.

ListBox displaying integers
ToString displays the class name
WeaponDefinitionListBoxItem displaying custom text
ComboBox displaying WeaponDefinition ToString