| name | mvux |
| description | MVUX (Model-View-Update-eXtended) architecture for Uno Platform: immutable records, reactive feeds/states, FeedView, commands, selection, messaging, and pagination. Use when: (1) Creating MVUX models with IFeed/IState/IListFeed/IListState, (2) Displaying async data with FeedView, (3) Implementing two-way binding with states, (4) Working with commands, selection, or messaging, (5) Debugging blank FeedView or missing command generation. Do NOT use for: MVVM patterns (use CommunityToolkit.Mvvm directly), general XAML layout (see winui-xaml), navigation (see uno-navigation). |
| license | MIT |
| metadata | {"version":"1.0.0","author":"Uno Platform","category":"uno-platform-mvux","tags":["mvux","reactive","feeds","states","uno-platform","immutable"]} |
MVUX — Model-View-Update-eXtended
Reactive architecture for Uno Platform apps. Models are immutable partial record types that expose IFeed<T> (read-only) and IState<T> (read-write) properties. A ViewModel is code-generated from each Model to bridge immutable data with XAML data binding.
Quick Reference
- Models MUST be
partial record with a Model suffix (e.g., MainModel) — the generator creates MainViewModel
- Data entities SHOULD be
record types (immutable, value equality)
- Use
IFeed<T> for read-only async data, IState<T> for mutable/two-way bound data
- Use
IListFeed<T> for read-only collections, IListState<T> for mutable collections
- Set
DataContext to the generated ViewModel, not the Model: new MainViewModel(...)
- Inside
FeedView templates, access data via {Binding Data.PropertyName}
- Public async methods on the Model auto-generate
IAsyncCommand properties on the ViewModel
- States require
this as owner for lifecycle management: State<string>.Empty(this)
- Records with a property named
Id or Key auto-generate IKeyEquatable<T> — needed for messaging and selection
- Requires
<UnoFeatures>MVUX</UnoFeatures> in the project file
Key Concepts
MVUX vs MVVM
| Aspect | MVVM | MVUX |
|---|
| Data flow | Bidirectional | Unidirectional (immutable → generated ViewModel bridges binding) |
| Model type | class with INotifyPropertyChanged | partial record (immutable) |
| State management | Manual property change notifications | Automatic via IFeed<T> / IState<T> |
| Async states | Manual (loading flags, try/catch) | Built-in (loading/error/none/value) |
| Commands | Manual ICommand implementations | Auto-generated from public methods |
| Collections | ObservableCollection<T> | IListFeed<T> / IListState<T> |
Type Decision Tree
Need to display data from a service?
├── Single item, read-only? → IFeed<T>
├── Single item, user can edit? → IState<T>
├── Collection, read-only? → IListFeed<T>
└── Collection, user can add/remove/edit? → IListState<T>
Project Setup
MVUX requires the MVUX UnoFeature in your project file:
<UnoFeatures>MVUX</UnoFeatures>
This pulls in the Uno.Extensions.Reactive packages and enables the source generator.
Model Structure
public partial record MainModel(IWeatherService WeatherService)
{
public IFeed<WeatherInfo> CurrentWeather =>
Feed.Async(WeatherService.GetCurrentWeather);
public IState<string> City => State<string>.Empty(this);
public IFeed<WeatherInfo> CityWeather =>
City.SelectAsync(WeatherService.GetWeatherForCity);
public async ValueTask Refresh(CancellationToken ct)
{
await City.UpdateAsync(_ => "Montréal", ct);
}
}
<Page xmlns:mvux="using:Uno.Extensions.Reactive.UI">
<mvux:FeedView Source="{Binding CurrentWeather}">
<DataTemplate>
<TextBlock Text="{Binding Data.Temperature}" />
</DataTemplate>
</mvux:FeedView>
</Page>
public MainPage()
{
InitializeComponent();
DataContext = new MainViewModel(new WeatherService());
}
Critical Patterns
FeedView with All Templates
<mvux:FeedView Source="{Binding CurrentWeather}">
<mvux:FeedView.ValueTemplate>
<DataTemplate>
<TextBlock Text="{Binding Data.Temperature}" />
</DataTemplate>
</mvux:FeedView.ValueTemplate>
<mvux:FeedView.ProgressTemplate>
<DataTemplate>
<ProgressRing />
</DataTemplate>
</mvux:FeedView.ProgressTemplate>
<mvux:FeedView.ErrorTemplate>
<DataTemplate>
<TextBlock Text="An error occurred" />
</DataTemplate>
</mvux:FeedView.ErrorTemplate>
<mvux:FeedView.NoneTemplate>
<DataTemplate>
<TextBlock Text="No data available" />
</DataTemplate>
</mvux:FeedView.NoneTemplate>
</mvux:FeedView>
<TextBlock Text="{Binding CurrentWeather.Temperature}" />
Two-Way Binding with IState
public IState<string> City => State<string>.Empty(this);
<TextBox Text="{Binding City, Mode=TwoWay}" />
public IFeed<string> City => Feed.Async(async ct => "Montréal");
State Updates Must Be Awaited
public async ValueTask SetCity(CancellationToken ct)
{
await City.UpdateAsync(_ => "Toronto", ct);
}
public void SetCity()
{
_ = City.UpdateAsync(_ => "Toronto");
}
ListView with IListFeed (No FeedView Needed)
<ListView ItemsSource="{Binding People}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FirstName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Command with Feed Parameter
public IFeed<int> CounterValue => ...
public async ValueTask ResetCounter(int counterValue, CancellationToken ct)
{
}
<Button Command="{Binding ResetCounter}" Content="Reset" />
Common Mistakes
Model declaration:
- Forgetting
partial on the record — the source generator cannot produce the ViewModel
- Missing
Model suffix — the generator won't match the class (configurable via [ReactiveBindable] or [ImplicitBindables])
- Setting
DataContext to the Model instead of the generated ViewModel
- Using
class instead of record — loses immutability guarantees
Feeds and states:
- Using
IFeed<T> when IState<T> is needed — feeds are read-only, two-way binding silently does nothing
- Using
IState<T> when IFeed<T> suffices — states hold cached values and are heavier
- Forgetting
this in state factory methods (State<T>.Empty(this)) — required for lifecycle management
- Not awaiting
UpdateAsync / SetAsync — updates may be lost or errors swallowed
- Using
Feed<List<T>> instead of IListFeed<T> — operators won't work on individual items
FeedView:
- Binding to
{Binding PropertyName} inside FeedView templates instead of {Binding Data.PropertyName}
- Not providing
ProgressTemplate — default progress ring may not match your design
- Empty collections show
NoneTemplate, not ValueTemplate — this is by design for IListFeed<T>
Commands:
- Expecting a command from a method that returns a value (non-void, non-Task/ValueTask) — not generated
- Feed parameter name/type mismatch — the parameter won't be resolved from the feed and will be treated as
CommandParameter
Records and key equality:
- Using
set instead of init on record properties — breaks immutability
- Missing
partial on data records that need IKeyEquatable<T> auto-generation
- No
Id or Key property on records used with messaging — entities can't be matched for updates
Related Skills
| Skill | Use instead when... |
|---|
winui-xaml | Working with XAML layout, binding syntax, or performance (not MVUX-specific) |
uno-platform-agent | Creating a new Uno Platform project from scratch |
uno-navigation | Setting up page navigation and routing |
uno-toolkit | Using Toolkit controls (AutoLayout, SafeArea, TabBar) |
uno-material | Configuring Material Design theme and styling |
dotnet-csharp | General C# best practices not specific to MVUX |
Detailed References
Read the reference file matching your current task:
- references/01-records-code-generation.md — Read when designing data models, understanding immutability requirements, or configuring key equality
- references/02-feeds.md — Read when creating IFeed, using FeedView, or applying feed operators (Select, Where, SelectAsync)
- references/03-states.md — Read when implementing two-way binding, updating state programmatically, or subscribing to state changes
- references/04-collections.md — Read when working with IListFeed, IListState, or implementing single/multi-item selection
- references/05-commands-actions.md — Read when configuring command generation, using feed parameters, messaging, or CRUD sync
- references/06-advanced-patterns.md — Read when implementing pagination, infinite scroll, cursor-based APIs, or offset pagination
Docs Fallback
If the encoded knowledge above may be outdated, use MCP to fetch the latest:
uno_platform_docs_search("MVUX overview Model View Update")
uno_platform_docs_search("MVUX Feed IFeed async")
uno_platform_docs_search("MVUX State IState mutable binding")
uno_platform_docs_search("MVUX FeedView control display")
uno_platform_docs_search("MVUX commands generation")
uno_platform_docs_search("MVUX ListFeed collection")
uno_platform_docs_search("MVUX ListState mutable collection")
uno_platform_docs_search("MVUX selection")
uno_platform_docs_search("MVUX pagination PaginatedAsync")
uno_platform_docs_search("MVUX messaging EntityMessage")