Luke.Mvux.Wpf 0.0.7

dotnet add package Luke.Mvux.Wpf --version 0.0.7
                    
NuGet\Install-Package Luke.Mvux.Wpf -Version 0.0.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Luke.Mvux.Wpf" Version="0.0.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Luke.Mvux.Wpf" Version="0.0.7" />
                    
Directory.Packages.props
<PackageReference Include="Luke.Mvux.Wpf" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Luke.Mvux.Wpf --version 0.0.7
                    
#r "nuget: Luke.Mvux.Wpf, 0.0.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Luke.Mvux.Wpf@0.0.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Luke.Mvux.Wpf&version=0.0.7
                    
Install as a Cake Addin
#tool nuget:?package=Luke.Mvux.Wpf&version=0.0.7
                    
Install as a Cake Tool

Luke.Mvux

한국어

A standalone reimplementation of the Uno Platform MVUX pattern API (IFeed, IState, IListState, Option<T>, Message<T>, etc.) for WPF and Avalonia. Includes FeedView control and Roslyn source generator.

This project intentionally mirrors the API design (interface names, method signatures, type structures) of Uno Platform MVUX. The implementation was written from scratch for WPF and Avalonia — no source code was copied. This project has no official affiliation with the Uno Platform team.


Packages

Package Description Target
Luke.Mvux.Wpf FeedView control + source generator for WPF net8.0-windows / net10.0-windows
Luke.Mvux.Avalonia FeedView control + source generator for Avalonia net8.0 / net10.0

Features

  • IFeed<T> / IState<T> / IListState<T> — reactive async data streams with a 3-state Option<T> (Undefined / None / Some)
  • Message<T> with independent axesData, IsLoading, and Error can be combined simultaneously (e.g. stale data while refreshing)
  • FeedView control — renders Loading / Data / Error / None states declaratively in XAML
  • Roslyn Source Generator — write a partial record *Model, get a full *ViewModel (INPC, commands, list bindings) automatically
  • Selection synclistFeed.Selection(selectedState) + ListView with zero SelectedItem binding
  • ListFeed / ListState — full CRUD reactive list (Add, AddRange, InsertAt, Remove, Update, Set, Clear)

Quick Start

1. Install

WPF

dotnet add package Luke.Mvux.Wpf

Avalonia

dotnet add package Luke.Mvux.Avalonia

The source generator is bundled inside each package — no separate generator reference needed.

1.5 Initialize MVUX once at app startup

Selection sync is registered at platform startup. Add UseMvux() once:

WPF (App.xaml.cs)

using Luke.Mvux.Wpf;

protected override void OnStartup(StartupEventArgs e)
{
    this.UseMvux();
    base.OnStartup(e);
}

Avalonia (Program.cs)

using Luke.Mvux.Avalonia;

public static AppBuilder BuildAvaloniaApp() =>
    AppBuilder.Configure<App>()
        .UseMvux()
        .UsePlatformDetect()
        .LogToTrace();

2. Write a Model

// WeatherModel.cs
public partial record WeatherModel(IWeatherService WeatherService)
{
    // IState<T>: readable/writable reactive state
    public IState<string> City => State.Value(this, () => "Seoul");

    // IFeed<T>: re-executes automatically whenever City changes
    public IFeed<WeatherInfo> CurrentWeather =>
        City.SelectAsync((city, ct) => WeatherService.GetWeatherAsync(city, ct));

    // IListState<T>: full-CRUD reactive list
    public IListState<string> Favorites => ListState.Value(this, () => new List<string>());
    public IState<string> SelectedFavorite => State<string>.Empty(this);

    // Selection: auto-clears SelectedFavorite when the item is removed
    public IListFeed<string> FavoritesWithSelection => Favorites.Selection(SelectedFavorite);

    // Commands: public ValueTask/Task, 0 params or CancellationToken only
    public async ValueTask AddFavorite(CancellationToken ct)
    {
        var city = await City;
        if (city != null) await Favorites.AddAsync(city, ct);
    }

    public async ValueTask GoToSelected(CancellationToken ct)
    {
        var selected = await SelectedFavorite;
        if (selected != null) await City.SetAsync(selected, ct);
    }
}

The source generator produces WeatherViewModel automatically with:

  • string? City { get; set; } — two-way INPC property wired to IState<string>
  • IFeed<WeatherInfo> CurrentWeather — raw feed passthrough for FeedView
  • ObservableCollection<string> Favorites / FavoritesWithSelection — list bindings
  • ICommand AddFavorite / ICommand GoToSelected

3. Wire up in code-behind

public MainWindow()
{
    InitializeComponent();
    DataContext = new WeatherViewModel(new MyWeatherService());
}

4. Bind in XAML

WPF:

<Window xmlns:lib="clr-namespace:Luke.Mvux.Wpf;assembly=Luke.Mvux.Wpf">

    
    <TextBox Text="{Binding City, UpdateSourceTrigger=PropertyChanged}" />

    
    <lib:FeedView x:Name="WeatherFeed" Source="{Binding CurrentWeather}">

        <lib:FeedView.LoadingTemplate>
            <DataTemplate>
                <TextBlock Text="Loading..." />
            </DataTemplate>
        </lib:FeedView.LoadingTemplate>

        <lib:FeedView.FeedDataTemplate>
            <DataTemplate>
                
                
                
                
                <StackPanel>
                    <TextBlock Text="{Binding Data.City}" FontSize="24" FontWeight="Bold" />
                    <TextBlock Text="{Binding Data.Temperature}" FontSize="48" />
                </StackPanel>
            </DataTemplate>
        </lib:FeedView.FeedDataTemplate>

        <lib:FeedView.ErrorTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Foreground="Red" Text="{Binding Error.Message}" />
                    <Button Content="Retry" Command="{Binding Refresh}" />
                </StackPanel>
            </DataTemplate>
        </lib:FeedView.ErrorTemplate>

    </lib:FeedView>

    
    <Button Content="Refresh" Command="{Binding RefreshCommand, ElementName=WeatherFeed}" />

    
    <ListView ItemsSource="{Binding FavoritesWithSelection}" />

</Window>

Avalonia — same XAML structure, different namespace and ListBox instead of ListView:

<Window xmlns:lib="clr-namespace:Luke.Mvux.Avalonia;assembly=Luke.Mvux.Avalonia">

    
    <lib:FeedView x:Name="WeatherFeed" Source="{Binding CurrentWeather}">
        ...
    </lib:FeedView>

    
    <ListBox ItemsSource="{Binding FavoritesWithSelection}" />

</Window>

API Overview

Option<T>

State Meaning
Undefined Not yet known (initial / before first load)
None Explicitly empty (user cleared it)
Some(T) Has a value

Message<T>

Data, IsLoading, and Error are independent axes — they can be combined:

Message<T>.Initial                       // Undefined + IsLoading=true
Message<T>.WithData(value)               // Some(value)
Message<T>.WithData(value, isLoading: true) // stale data while refreshing
Message<T>.Errored(ex)                   // Error
Message<T>.None()                        // explicitly empty

Feed operators

feed.Select(x => ...)                     // IFeed<TResult>
feed.SelectAsync((x, ct) => ...)          // IFeed<TResult>, async transform
feed.Where(x => ...)                      // IFeed<T>
feed.ForEachAsync(action, ct)             // subscribe loop

listFeed.Select(item => ...)              // IListFeed<TResult> (item-level)
listFeed.Where(item => ...)               // IListFeed<T>       (item-level)
listFeed.Selection(selectedState)         // single selection sync
listFeed.Selection(selectedItemsState)    // multi-selection sync

ListFeed.Async(ct => WeatherService.GetWeatherListAsync(ct))
    .WhenSelected(selectedState)          // single selection sync on list feed
ListFeed.Async(ct => WeatherService.GetWeatherListAsync(ct))
    .WhenSelected(selectedItemsState)     // multi-selection sync on list feed

IListState<T>

await list.AddAsync(item);
await list.AddRangeAsync(items);
await list.InsertAtAsync(index, item);
await list.RemoveAsync(item);
await list.RemoveAsync(predicate);
await list.UpdateAsync(oldItem, newItem);
await list.UpdateAsync(predicate, updater);   // extension: first match
await list.UpdateAllAsync(predicate, updater); // extension: all matches
await list.SetAsync(items);
await list.ClearAsync();

Project Structure

src/
  Luke.Mvux/                — Core abstractions (platform-agnostic, net8.0+)
  Luke.Mvux.Generators/     — Roslyn IIncrementalGenerator (netstandard2.0)
  Luke.Mvux.Wpf/            — WPF controls + Generator bundle (net8.0-windows / net10.0-windows)
  Luke.Mvux.Avalonia/       — Avalonia controls + Generator bundle (net8.0 / net10.0)
samples/
  Wpf.Sample/             — WPF demo app (weather + favorites)
  Avalonia.Sample/        — Avalonia demo app (weather + favorites)
tests/
  Mvux.Core.Tests/        — Unit tests (xUnit)

License

This project is licensed under the Apache License 2.0 — see the LICENSE file for details.

Attribution

This project reimplements the API design of Uno Platform MVUX (uno.extensions) independently for WPF and Avalonia. uno.extensions is distributed under the Apache License 2.0.

Copyright (c) 2021-present nventive and Uno Platform contributors

Licensed under the Apache License, Version 2.0

The source code of uno.extensions is not included in this repository. The interface design and pattern structure were followed; the WPF and Avalonia implementation code was written from scratch.

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed.  net10.0-windows7.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0-windows7.0

    • No dependencies.
  • net8.0-windows7.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.7 121 5/29/2026
0.0.6 107 5/28/2026
0.0.5 114 5/28/2026
0.0.4 123 5/27/2026
0.0.3 115 5/26/2026
0.0.2 104 5/24/2026
0.0.1 121 5/24/2026 0.0.1 is deprecated because it has critical bugs.