Repository navigation
Usage
This section covers how to use Myra UI Generator in your projects.
The generator processes XML files marked as AdditionalFiles in your .csproj:
<ItemGroup>
<AdditionalFiles Include="Content/UI/*.xml" />
</ItemGroup>You can include:
- Individual files:
Include="Content/UI/MainMenu.xml" - Wildcards:
Include="Content/UI/*.xml" - Recursive:
Include="Content/UI/**/*.xml" - Multiple patterns: Multiple
<AdditionalFiles>entries
For each XML file, the generator creates a partial class:
-
File:
TitleScreen.xml→ Class:TitleScreenUI -
Location: Generated in
obj/directory (hidden by default in IDEs) -
Namespace: As configured (default:
GeneratedUI)
Every generated class has an Initialize(Widget root) method that binds widgets:
public void Initialize(Widget root)
{
StartButton = root.FindChildById("StartButton") as Button;
TitleLabel = root.FindChildById("TitleLabel") as Label;
// ... more widgets
}Important: You must call Initialize() after loading the XML and before using the properties.
After initialization, access widgets through strongly-typed properties:
var ui = new TitleScreenUI();
ui.Initialize(project.Root);
// All properties are strongly-typed
ui.StartButton.Click += OnStartClicked;
ui.TitleLabel.Text = "Welcome!";
ui.ExitButton.IsEnabled = false;Let's create a complete working example from scratch.
Create Content/UI/MainMenu.xml:
<Project>
<VerticalStackPanel>
<Label Id="TitleLabel" Text="My Awesome Game" />
<Button Id="NewGameButton" Content="New Game" />
<Button Id="LoadGameButton" Content="Load Game" />
<Button Id="SettingsButton" Content="Settings" />
<Button Id="ExitButton" Content="Exit" />
</VerticalStackPanel>
</Project>Option A: Add to .csproj
<ItemGroup>
<AdditionalFiles Include="Content/UI/*.xml" />
</ItemGroup>Option B: Use .editorconfig (create in project root)
[*.cs]
myra_ui_generator.namespace = MyGame.UI.Generated
myra_ui_generator.xml_directory = Content/UIBuild the project. The generator will:
- Find
MainMenu.xml - Extract widgets with
Idattributes - Generate
MainMenuUI.g.cs
using MyGame.UI.Generated;
using Myra.Graphics2D.UI;
using Myra.Graphics2D;
public class GameScreen
{
private MainMenuUI _ui;
public void Load()
{
// Load the XML
var project = UiLoader.Load("MainMenu.xml");
// Create and initialize the generated class
_ui = new MainMenuUI();
_ui.Initialize(project.Root);
// Set up event handlers
_ui.NewGameButton.Click += OnNewGameClicked;
_ui.LoadGameButton.Click += OnLoadGameClicked;
_ui.SettingsButton.Click += OnSettingsClicked;
_ui.ExitButton.Click += OnExitClicked;
// Customize UI
_ui.TitleLabel.TextColor = Color.White;
}
private void OnNewGameClicked(object sender, EventArgs e)
{
// Start new game
}
// ... other event handlers
}public void Draw()
{
// Render the UI root (from project.Root)
// This depends on your rendering setup
}Organize UI classes by screen:
public class ScreenManager
{
private MainMenuUI _mainMenu;
private SettingsUI _settings;
private GameHUDUI _hud;
public void ShowMainMenu()
{
var project = UiLoader.Load("MainMenu.xml");
_mainMenu = new MainMenuUI();
_mainMenu.Initialize(project.Root);
// ... setup
}
public void ShowSettings()
{
var project = UiLoader.Load("Settings.xml");
_settings = new SettingsUI();
_settings.Initialize(project.Root);
// ... setup
}
}Keep event handlers organized:
public class MainMenuScreen
{
private MainMenuUI _ui;
public void Initialize()
{
var project = UiLoader.Load("MainMenu.xml");
_ui = new MainMenuUI();
_ui.Initialize(project.Root);
SetupEventHandlers();
}
private void SetupEventHandlers()
{
_ui.NewGameButton.Click += OnNewGame;
_ui.LoadGameButton.Click += OnLoadGame;
_ui.SettingsButton.Click += OnSettings;
_ui.ExitButton.Click += OnExit;
}
private void OnNewGame(object sender, EventArgs e) { /* ... */ }
private void OnLoadGame(object sender, EventArgs e) { /* ... */ }
private void OnSettings(object sender, EventArgs e) { /* ... */ }
private void OnExit(object sender, EventArgs e) { /* ... */ }
}Initialize widgets with default values:
public void InitializeUI()
{
var project = UiLoader.Load("GameHUD.xml");
_hud = new GameHUDUI();
_hud.Initialize(project.Root);
// Set initial values
_hud.HealthBar.Value = 100;
_hud.ScoreLabel.Text = "0";
_hud.AmmoLabel.Text = "30";
}Handle multiple UI files in one class:
public class GameUI
{
private MainMenuUI _mainMenu;
private PauseMenuUI _pauseMenu;
private GameHUDUI _hud;
public void LoadAll()
{
LoadMainMenu();
LoadPauseMenu();
LoadHUD();
}
private void LoadMainMenu()
{
var project = UiLoader.Load("MainMenu.xml");
_mainMenu = new MainMenuUI();
_mainMenu.Initialize(project.Root);
}
// ... similar for other UIs
}Use partial classes to extend generated code:
// In your own file: MainMenuUI.cs
public partial class MainMenuUI
{
public void Show()
{
// Custom logic
}
public void Hide()
{
// Custom logic
}
}-
XML Files: Use PascalCase (e.g.,
MainMenu.xml,SettingsScreen.xml) -
Widget IDs: Use PascalCase (e.g.,
StartButton,HealthBar,ScoreLabel) - Namespaces: Use your project's namespace convention
Content/
└── UI/
├── Menus/
│ ├── MainMenu.xml
│ └── PauseMenu.xml
├── Screens/
│ ├── TitleScreen.xml
│ └── GameOverScreen.xml
└── HUD/
└── GameHUD.xml
Only add Id attributes to widgets you need to access from code:
- ✅ Buttons you'll attach click handlers to
- ✅ Labels you'll update dynamically
- ✅ Input fields you'll read values from
- ✅ Progress bars you'll update
- ❌ Static decorative elements
- ❌ Layout containers you don't access directly
Always check for null after initialization:
_ui.Initialize(project.Root);
if (_ui.StartButton == null)
{
throw new InvalidOperationException("StartButton not found in UI");
}Or use null-conditional operators:
_ui.StartButton?.Click += OnStartClicked;-
Load Once: Load XML files once and reuse the
Projectobject - Cache Instances: Reuse UI class instances when possible
- Lazy Initialization: Only initialize UI when needed
- Batch Updates: Update multiple widgets together when possible
// Good: Organized by responsibility
public class MainMenuScreen
{
private MainMenuUI _ui;
public void Load() { /* ... */ }
public void Update() { /* ... */ }
public void Draw() { /* ... */ }
private void SetupHandlers() { /* ... */ }
}
// Avoid: Everything in one method
public void DoEverything()
{
// 200 lines of mixed initialization, handlers, and logic
}- See Examples for complete working code
- Read the API Reference
- Check Supported Widgets
- Learn Advanced Topics