Repository navigation
Advanced
Advanced usage patterns and techniques for Myra UI Generator.
The generator has built-in support for common Myra widget types. When it encounters an unknown widget type, it falls back to the base Widget type.
If you use a custom widget or a widget type not yet supported:
Generated Code:
public Widget CustomWidget { get; private set; }Usage with Type Casting:
_ui.Initialize(project.Root);
// Cast to your specific type
var custom = _ui.CustomWidget as MyCustomWidgetType;
if (custom != null)
{
custom.CustomProperty = value;
}Since generated classes are partial, you can add helper methods:
// Your code: CustomWidgetUI.cs
public partial class CustomWidgetUI
{
public MyCustomWidgetType GetCustomWidget()
{
return CustomWidget as MyCustomWidgetType;
}
public bool IsCustomWidgetValid()
{
return CustomWidget is MyCustomWidgetType;
}
}If you need support for additional widget types:
- Check if the widget is already supported (see Supported Widgets)
- If not, you can:
- Use the
Widgetfallback and cast manually - Request support by opening an issue on GitHub
- Contribute support by submitting a pull request
- Use the
Organizing generated code with proper namespaces is important for large projects.
For a single project, use a clear namespace hierarchy:
[*.cs]
myra_ui_generator.namespace = MyGame.UI.GeneratedStructure:
MyGame.UI.Generated
├── MainMenuUI
├── SettingsUI
├── GameHUDUI
└── PauseMenuUI
For solutions with multiple projects, each can have its own namespace:
Project 1: MyGame.Client
[*.cs]
myra_ui_generator.namespace = MyGame.Client.UI.GeneratedProject 2: MyGame.Editor
[*.cs]
myra_ui_generator.namespace = MyGame.Editor.UI.GeneratedIf you have a shared UI library project:
Shared.UI Project:
[*.cs]
myra_ui_generator.namespace = MyGame.Shared.UI.GeneratedOther Projects: Reference the shared project and use:
using MyGame.Shared.UI.Generated;- Be Consistent: Use the same namespace pattern across your project
- Include "Generated": Makes it clear these are auto-generated files
- Match Project Structure: Align with your project's namespace conventions
- Avoid Conflicts: Ensure namespaces don't conflict with your own code
Myra UI Generator is designed for zero runtime overhead. All code generation happens at compile time.
What Happens:
- Generator runs during compilation
- XML files are parsed
- C# code is generated
- Generated code is compiled with your project
Runtime Impact: None - Generated code is just regular C# classes
Typical Impact:
- Small projects (< 10 XML files): Negligible (< 1 second)
- Medium projects (10-50 XML files): < 5 seconds
- Large projects (50+ XML files): < 10 seconds
Optimization Tips:
- Only include XML files you actually use
- Use wildcards efficiently (avoid overly broad patterns)
- Keep XML files organized in specific directories
During Build:
- Generator loads XML files into memory
- Memory usage is proportional to XML file sizes
- Typically very small (< 1MB for most projects)
At Runtime:
- No generator code runs
- Only your generated classes exist (same as hand-written code)
For projects with many UI files:
-
Organize by Feature:
Content/UI/ ├── Menus/ ├── HUD/ ├── Dialogs/ └── Screens/ -
Use Specific Patterns:
<!-- Good: Specific --> <AdditionalFiles Include="Content/UI/Menus/*.xml" /> <!-- Avoid: Too broad --> <AdditionalFiles Include="**/*.xml" />
-
Consider Separate Projects: Split UI into separate projects if it becomes unwieldy
Generated classes are minimal:
- Per Widget: ~3 lines (property declaration + initialization)
- Per File: ~10-20 lines base + 3 lines per widget
- Example: 10 widgets = ~40-50 lines of generated code
This is negligible compared to typical project sizes.
public class UIService
{
private readonly IServiceProvider _services;
public MainMenuUI CreateMainMenu()
{
var project = UiLoader.Load("MainMenu.xml");
var ui = new MainMenuUI();
ui.Initialize(project.Root);
// Inject dependencies if needed
// ui.SetDependencies(_services);
return ui;
}
}public class GameState
{
public int Score { get; set; }
public int Health { get; set; }
// ... other state
}
public class GameHUD
{
private GameHUDUI _ui;
private GameState _state;
public void UpdateFromState(GameState state)
{
_state = state;
_ui.ScoreLabel.Text = $"Score: {state.Score}";
_ui.HealthBar.Value = state.Health;
}
}public class MainMenuViewModel
{
public string Title { get; set; } = "My Game";
public bool CanStartNewGame { get; set; } = true;
// ... other properties
}
public class MainMenuView
{
private MainMenuUI _ui;
private MainMenuViewModel _viewModel;
public void Bind(MainMenuViewModel viewModel)
{
_viewModel = viewModel;
UpdateUI();
}
private void UpdateUI()
{
_ui.TitleLabel.Text = _viewModel.Title;
_ui.NewGameButton.IsEnabled = _viewModel.CanStartNewGame;
}
}Generated files are in the obj/ directory:
obj/
└── Debug/
└── net6.0/
└── generated/
└── MyraUIGenerator/
└── MyraUIGenerator.MyraUIGenerator/
├── MainMenuUI.g.cs
└── SettingsUI.g.cs
To View:
- Show all files in Solution Explorer (Visual Studio)
- Navigate to
obj/Debug/{framework}/generated/ - Or use "Go to Definition" on a generated class
-
Check Diagnostics: Look for
MYRAdiagnostic codes in build output -
Verify XML: Ensure XML files are valid and have
Idattributes - Check Configuration: Verify namespace and directory settings
- Inspect Generated Code: Look at actual generated files if behavior is unexpected
-
Null Checks: Always check for null after
Initialize()
Widget is null after Initialize:
- Widget not found in XML (check
Idattribute) - Widget type mismatch (check XML element name)
- Widget is nested too deeply (ensure
FindChildByIdcan find it)
Wrong namespace in generated code:
- Check
.editorconfigconfiguration - Verify configuration is in project root
- Rebuild project after changing configuration
XML file not being processed:
- Check
AdditionalFilesin.csproj - Verify file path matches
xml_directorysetting - Check file extension is
.xml - Look for
MYRA003diagnostic message
- Review Troubleshooting for common issues
- Check Reference for complete API documentation
- See Examples for more patterns