Feeds in MVUX

In the past three posts (Getting Started, Comparison with MVVM and Incremental Loading) I’ve talked about the use of Model-View-Update-eXtended (MVUX). In this post we’re going look at feeds, which is one of the key components of MVUX.

What’s a Feed

In simple terms, a feed represents a stream of values, much like an Observable (from Reactive). A feed can be created from any asynchronous operation that returns a value, for example loading data from storage, or a web request. For example, the following feed returns a random number after a 2 second delay.

public partial record MainModel
{
    public IFeed<int> RandomNumber => Feed.Async(async ct => {
        await Task.Delay(2000);
        return (int)(Random.Shared.NextDouble() * 10000);
    });
}

Feeds can also be generated from an operation that returns an IAsyncEnumerable, which is useful for returning a series of values over time. For example, the following feed is created from the RandomSequence method that will continue to return new random numbers until the CancellationToken is cancelled.

public IFeed<int> RandomNumberSequence => Feed.AsyncEnumerable(RandomSequence);

private async IAsyncEnumerable<int> RandomSequence([EnumeratorCancellation] CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        await Task.Delay(2000);
        yield return (int)(Random.Shared.NextDouble() * 10000);
    }
}

Now that we’ve seen the definition of a couple of feeds, let’s turn to look at how we can use a feed within an application. Firstly, since feeds are all asynchronous they can be awaited in order to get the value of the feed.

public async Task WhatsTheNextNumber(CancellationToken ct)
{
    var next = await RandomNumber;
    ...
}

It’s important to note that awaiting the feed doesn’t start the feed, nor does it cause the feed to refresh. For example, in the following code both next and next_again will have the same value

public async Task WhatsTheNextNumber(CancellationToken ct)
{
    var next = await RandomNumber;
    var next_again = await RandomNumber;
    ...
}

Another way the feed can be consumed is in XAML, such as the following that binds the Text property on a TextBlock to the RandomNumber feed.

<TextBlock Text="{Binding RandomNumber}" />

However, unlike in conventional MVVM based applications, the DataContext of the page isn’t set to an instance of our MainModel. Instead, MVUX generates a bindable proxy, BindableMainModel, that is set to the DataContext of the page.

public MainPage()
{
    this.InitializeComponent();

    DataContext = new BindableMainModel();
}

Note that if you’re using Uno.Extensions Navigation you don’t need to worry about manually creating instances of the BindableMainModel as the dependency injection container is used to create new instances as they’re required.

You can think of the bindable proxies as the glue that makes it possible to data bind to the feeds. As the data in the feed changes, the corresponding bindable proxy raises the appropriate PropertyChanged event so that the data binding engine is able to update any elements that are data bound to the feed.

In this post you’ve seen a brief overview of what a feed is in the context of Model-View-Update-eXtended (MVUX) and how it can be used in your code. In subsequent posts we’ll dig further into how else feeds can be used and how they relate to state and user input.

2 thoughts on “Feeds in MVUX”

Leave a comment