Skip to content

StarryXYJ/AutoSettingUI

Repository files navigation

AutoSettingUI

NuGet NuGet NuGet NuGet NuGet NuGet Downloads License

AutoSettingUI is a .NET library that automatically generates settings UI panels from plain C# objects decorated with attributes. Annotate a class, hand it to the control, and a fully functional settings form is rendered — no manual UI wiring required.

Features

  • 🎨 Multi-framework — Avalonia, Ursa (Avalonia), and WPF panels included
  • Attribute-driven — Decorate properties with attributes to customize rendering
  • AOT-compatible — Incremental Roslyn Source Generator enables full Native AOT and trimming support
  • 🔄 MVVM Support — Works with CommunityToolkit.Mvvm [ObservableProperty]
  • 🌐 i18n Support — Built-in localization service with dynamic language switching powered by DynamicLocalization
  • 🔌 Extensible — Inject custom providers and accessors
  • 🧭 Built-in navigation — Sidebar tree navigation to sections
  • 🎯 Extended Controls — ColorPicker, DatePicker, TimePicker, NumericUpDown, and more

Installation

<!-- Avalonia -->
<PackageReference Include="AutoSettingUI.Avalonia" />

<!-- Ursa (Avalonia with Ursa theme) -->
<PackageReference Include="AutoSettingUI.Ursa" />

<!-- WPF -->
<PackageReference Include="AutoSettingUI.WPF" />

<!-- AOT Support (Optional) -->
<PackageReference Include="AutoSettingUI.Generator" />

Target Frameworks: net8.0; net9.0; net10.0 (WPF: net8.0-windows; net9.0-windows; net10.0-windows)

Avalonia: AutoSettingUI.Avalonia requires Avalonia >= 11.0.0. AutoSettingUI.Ursa requires Avalonia >= 11.1.1 (Ursa dependency).

Quick Start

1. Add Style References (Avalonia/Ursa only)

⚠️ Important: For Avalonia and Ursa projects, add the theme style reference to App.axaml.

Avalonia:

<Application.Styles>
    <FluentTheme />
    <StyleInclude Source="avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml"/>
    <StyleInclude Source="avares://AutoSettingUI.Avalonia/Themes/Generic.axaml"/>
</Application.Styles>

Ursa:

<Application.Styles>
    <u-semi:SemiTheme Locale="zh-CN" />
    <StyleInclude Source="avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml"/>
    <StyleInclude Source="avares://AutoSettingUI.Ursa/Themes/Generic.axaml"/>
</Application.Styles>

2. Define a Settings Model

using AutoSettingUI.Core.Attributes;
using AutoSettingUI.Avalonia.Attributes; // or AutoSettingUI.Ursa.Attributes

[SettingUI]
[MainHeader("Application Settings")]
public class AppSettings
{
    [Title("Application Name")]
    public string AppName { get; set; } = "My Application";

    [Title("Volume")]
    [Range(0, 100)]
    public int Volume { get; set; } = 50;

    [Title("Enable Logging")]
    [CheckBox]
    public bool EnableLogging { get; set; }

    [Title("Font Size")]
    [NumericUpDown(Minimum = 8, Maximum = 32)]
    public int FontSize { get; set; } = 14;
}

Using with CommunityToolkit.Mvvm

using CommunityToolkit.Mvvm.ComponentModel;

[SettingUI]
[MainHeader("Application Settings")]
public partial class ApplicationSettings : ObservableObject
{
    [Title("Application Name")]
    [ObservableProperty]
    private string _appName = "My Application";

    [Title("Enable Logging")]
    [ObservableProperty]
    private bool _enableLogging;
}

3. Bind the Panel

Avalonia:

<Window xmlns:auto="clr-namespace:AutoSettingUI.Avalonia.Controls;assembly=AutoSettingUI.Avalonia">
    <auto:AvaloniaAutoSettingPanel Targets="{Binding Targets}" />
</Window>

Ursa:

<Window xmlns:ursa="clr-namespace:AutoSettingUI.Ursa.Controls;assembly=AutoSettingUI.Ursa">
    <ursa:UrsaAutoSettingPanel Targets="{Binding Targets}" />
</Window>

WPF:

<Window xmlns:auto="clr-namespace:AutoSettingUI.WPF.Controls;assembly=AutoSettingUI.WPF">
    <auto:WpfAutoSettingPanel Targets="{Binding Targets}" />
</Window>

ViewModel:

public class MainViewModel
{
    public IEnumerable<object> Targets { get; } = new object[] { new AppSettings() };
}

4. AOT Support (Optional)

For Native AOT or trimming, the generator is picked up automatically. To force registration:

using AutoSettingUI.Core.Registry;
using AutoSettingUI.Generated;

AotSettingRegistry.Provider = new GeneratedSettingProvider();
AotSettingRegistry.Accessor = AotSettingRegistry.Provider;

Internationalization (i18n)

AutoSettingUI supports dynamic language switching powered by DynamicLocalization.

Using Resource Keys

Set UseResourceKey = true on title attributes:

[SettingUI]
[MainHeader("Settings.Application", UseResourceKey = true)]
public class ApplicationSettings
{
    [Title("Settings.AppName", UseResourceKey = true)]
    public string AppName { get; set; } = "My Application";

    [Title("Settings.EnableLogging", UseResourceKey = true)]
    public bool EnableLogging { get; set; }
}

Setting Up Localization

1. Create resource files (.resx):

  • Strings.resx (default/English)
  • Strings.zh-CN.resx (Chinese Simplified)

2. Create a resource accessor class:

namespace YourApp.Resources;

public static class Strings
{
    public static System.Resources.ResourceManager ResourceManager { get; } 
        = new System.Resources.ResourceManager(
            "YourApp.Resources.Strings", 
            typeof(Strings).Assembly);
}

3. Configure the localization service:

using DynamicLocalization.Core;
using DynamicLocalization.Core.Providers;

public class MainViewModel
{
    public ICultureService LocalizationService { get; }

    public MainViewModel()
    {
        var cultureService = new CultureService();
        var resxProvider = new ResxLocalizationProvider();
        resxProvider.Initialize(new ResxLocalizationProviderOptions
        {
            ResourceType = typeof(Strings)
        });
        cultureService.RegisterProvider(resxProvider);
        LocalizationService = cultureService;
    }

    public void SwitchToEnglish() => LocalizationService.SetCulture("en");
    public void SwitchToChinese() => LocalizationService.SetCulture("zh-CN");
}

4. Bind to the panel:

<auto:AvaloniaAutoSettingPanel 
    Targets="{Binding Targets}"
    LocalizationService="{Binding LocalizationService}" />

Localization Providers

DynamicLocalization supports multiple data sources for translations:

Provider Description
ResxLocalizationProvider Uses .NET .resx resource files
JsonLocalizationProvider JSON file-based translations
Custom Provider Implement ILocalizationProvider for database, API, etc.

For more providers and advanced usage, see DynamicLocalization.

Available Attributes

Attribute Target Description
[SettingUI] Class Marks class for UI generation
[MainHeader] Class Sets section header title
[Title] Property Sets property label
[SubHeader] Property Creates a sub-section
[Hide] Property Excludes from UI
[Range] Property Numeric range (renders slider)
[ItemsSource] Property Dropdown items source
[ControlBinding] Property Custom control binding
[ReadOnly] Property Makes property read-only
[Password] Property Masks input (password box)
[Placeholder] Property Placeholder text for input
[Layout] Property Custom layout (width, height)
[Validation] Property Custom validation method
[DisplayOrder] Property Controls display order (lower = first)
[CollectionEditor] Property Configures collection editing with add/remove/reorder and selected item binding

Extended Controls

Attribute Framework Description
[CheckBox] All Boolean property as CheckBox
[DatePicker] All DateTime with date picker
[TimePicker] Avalonia/Ursa TimeSpan with time picker
[NumericUpDown] Avalonia/Ursa Numeric input with up/down buttons
[ColorPicker] Avalonia/Ursa Color selection
[TagInput] Ursa String collection as tags
[IPv4Box] Ursa IP address input

Note: ColorPicker requires <StyleInclude Source="avares://Avalonia.Controls.ColorPicker/Themes/Fluent/Fluent.xaml"/> in App.axaml.

Custom Control Binding

The [ControlBinding] attribute allows you to specify custom controls for properties. There are several ways to use it:

1. Auto-bind with BindingProperty

Specify the control type and the property to bind to:

[ControlBinding(typeof(ProgressBar), "Value")]
public double ProgressValue { get; set; } = 50.0;

This automatically creates a two-way binding between ProgressValue and ProgressBar.Value.

2. Factory Method with Custom Binding

When you need full control over the binding (e.g., custom converters, validation), use a factory method without specifying BindingProperty:

[ControlBinding(typeof(Slider), FactoryMethod = nameof(CreateCustomSlider))]
public double CustomSliderValue { get; set; } = 75.0;

public Slider CreateCustomSlider()
{
    var slider = new Slider { Minimum = 0, Maximum = 100, Width = 200 };
    
    // Custom binding with your own logic
    slider.Bind(Slider.ValueProperty, 
        new Binding(nameof(CustomSliderValue)) 
        { 
            Source = this, 
            Mode = BindingMode.TwoWay 
        });
    
    return slider;
}

Important: When using a factory method without BindingProperty, the factory method is responsible for setting up bindings. The framework will not auto-bind.

3. Control Type Only (Auto-detect)

Specify only the control type, and the framework will attempt to auto-detect the binding property:

[ControlBinding(typeof(TextBox))]
public string AutoDetectedText { get; set; } = "Auto-detected binding";

The framework will try to bind to common properties like Text, Value, IsChecked, etc.

4. Complex Factory Method

Create fully customized controls with complete control over appearance and behavior:

[ControlBinding(typeof(StackPanel), FactoryMethod = nameof(CreateRatingControl))]
[ObservableProperty]
private int _rating = 3;

public StackPanel CreateRatingControl()
{
    var panel = new StackPanel { Orientation = Orientation.Horizontal };
    
    for (int i = 1; i <= 5; i++)
    {
        var starIndex = i;
        var button = new Button { Content = "★", FontSize = 24 };
        
        button.Click += (s, e) => Rating = starIndex;
        button.Bind(Button.ForegroundProperty,
            new Binding(nameof(Rating))
            {
                Source = this,
                Converter = new RatingConverter(starIndex)
            });
        
        panel.Children.Add(button);
    }
    
    return panel;
}

Binding Behavior Summary

BindingProperty FactoryMethod Behavior
Specified Not specified Auto-bind to specified property
Specified Specified Auto-bind to specified property (factory creates control)
Not specified Not specified Auto-detect common properties (WPF only)
Not specified Specified No auto-bind - factory handles binding

Creating Custom Control Attributes

Create reusable attributes by inheriting from ControlBindingAttribute:

[AttributeUsage(AttributeTargets.Property)]
public sealed class DatePickerAttribute : ControlBindingAttribute
{
    public DatePickerAttribute() 
        : base(typeof(CalendarDatePicker), "SelectedDate") { }
}

// Usage
[DatePicker]
public DateTime BirthDate { get; set; }

For complex controls with parameters:

public sealed class NumericUpDownAttribute : ControlBindingAttribute
{
    public double Minimum { get; set; }
    public double Maximum { get; set; } = 100;

    public NumericUpDownAttribute() 
        : base(typeof(NumericUpDown), "Value", nameof(CreateControl)) { }

    public Control CreateControl(Type propertyType) => new NumericUpDown
    {
        Minimum = (decimal)Minimum,
        Maximum = (decimal)Maximum
    };
}

// Usage
[NumericUpDown(Minimum = 0, Maximum = 100)]
public int ItemCount { get; set; }

Collection Editing

AutoSettingUI provides built-in collection editing support with add, remove, and reorder capabilities. You can also bind the selected item to a separate property for detailed editing.

Basic Collection Editing

[SettingUI]
public class Settings
{
    [Title("Tags")]
    public ObservableCollection<string> Tags { get; set; } = ["Important", "Work"];

    [Title("People")]
    public ObservableCollection<Person> People { get; set; } = new();
}

Selected Item Binding

Use SelectedItemProperty to bind the collection's selected item to a property. This enables detailed editing of the selected item:

[SettingUI]
public class Settings
{
    [Title("Tags")]
    [CollectionEditor(SelectedItemProperty = nameof(SelectedTag))]
    public ObservableCollection<string> Tags { get; set; } = ["Important", "Work"];

    [Title("Selected Tag")]
    [Description("The currently selected tag from the list above")]
    public string? SelectedTag { get; set; }

    [Title("People")]
    [CollectionEditor(SelectedItemProperty = nameof(SelectedPerson))]
    public ObservableCollection<Person> People { get; set; } = new();

    [Title("Selected Person")]
    [Description("Edit the selected person's details below")]
    public Person? SelectedPerson { get; set; }
}

When a user selects an item in the collection editor, the SelectedTag or SelectedPerson property is automatically updated. The UI will also reflect changes when these properties are modified programmatically.

Collection Editor Options

Property Type Description
AllowAdd bool Allow adding new items (default: true)
AllowRemove bool Allow removing items (default: true)
AllowReorder bool Allow reordering items (default: true)
AllowEditItems bool Allow inline editing of items (default: true)
SelectedItemProperty string Property name to bind selected item to
EditorTypeName string Custom editor type name
FactoryMethod string Factory method for custom editor

Read-Only Collection

[Title("Versions (Read-Only)")]
[CollectionEditor(AllowAdd = false, AllowRemove = false, AllowReorder = false)]
public ObservableCollection<string> Versions { get; set; } = ["1.0.0", "1.1.0", "2.0.0"];

Demo Applications

The repository includes demo applications showcasing all features:

Demo Framework Description
AutoSettingUI.Avalonia.CrossPlatform.Demo Avalonia Cross-platform (Desktop, Android, iOS, Browser)
AutoSettingUI.Ursa.Demo Ursa Ursa-themed Avalonia with extended controls
AutoSettingUI.Wpf.Demo WPF Windows Presentation Foundation

Demo Features

  • ✅ Dynamic language switching (English/Chinese)
  • ✅ Theme switching (Light/Dark/System)
  • ✅ Navigation toggle
  • ✅ Custom styled panels
  • ✅ Extended controls demonstration
  • ✅ Collection editing with selected item binding

Packages

Package Description Dependencies
AutoSettingUI.Avalonia Avalonia UI panel Core, Extension.Shared
AutoSettingUI.Ursa Ursa-themed Avalonia panel Core, Extension.Shared
AutoSettingUI.WPF WPF panel Core, Extension.Shared
AutoSettingUI.Generator Roslyn Source Generator for AOT Standalone (Analyzer)
AutoSettingUI.Core Attributes, interfaces, models DynamicLocalization.Core

Note: Core and Extension.Shared are automatically included when installing UI framework packages.

Documentation

Building

# Debug build
.\build-all.ps1

# Release build with NuGet packages
.\build-all.ps1 -Configuration Release -Pack

# Publish demo applications
.\publish-demo.ps1 -Framework Avalonia -Mode AOT
.\publish-demo.ps1 -Framework Ursa -Mode Normal
.\publish-demo.ps1 -Framework WPF -Mode Normal

License

MIT

About

Generate UI for settings and configs quickly and automatically

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors