How to create a list feed where values are pushed in

In this tutorial, you will learn how to create an MVUX project that displays stock data that is pushed in from a service using an Async Enumerable method.

In this tutorial, you will also learn how to create an MVUX project and utilization of feed (IFeed<T>) and the FeedView control to display data pushed in asynchronously from an IAsyncEnumerable<T>.

  • For our data, we're going to create a service that has an IAsyncEnumerable<T> method that returns periodic stock market updates.
  • You'll learn how to use a feed to asynchronously request this data from the service.
  • How to use the FeedView control to display the asynchronous data and automatically respond to the current feed status.

StockMarketApp Sample

You can find the code of this tutorial here.

Create the Model

  1. Create an MVUX project by following the steps in this tutorial, and name the project StockMarketApp..

  2. Add a class named StockMarketService.cs, and replace its content with the following:

    using System.Runtime.CompilerServices;
    
    namespace StockMarketApp;
    
    public partial record Stock(string Name, double Value);
    
    public class StockMarketService
    {
        public async IAsyncEnumerable<IImmutableList<Stock>> GetCurrentMarket(
            [EnumeratorCancellation] CancellationToken ct)
        {
            var rnd = new Random();
    
            while (!ct.IsCancellationRequested)
            {
                // return current stock-market info
                yield return _stocks.ToImmutableList();
    
                // this delays the next iteration by 5 seconds
                await Task.Delay(TimeSpan.FromSeconds(5), ct);
    
                // this updates the market prices
                // in a more realistic program
                // this would have taken place on the remote server
                for (int i = 0; i < _stocks.Count; i++)
                {
                    var stock = _stocks[i];
                    var increment = rnd.NextDouble();
    
                    _stocks[i] = stock with { Value = stock.Value + increment };
                }
            }
        }
    
        // this list is for the purpose of this demonstration
        // we're treating this variable as our database
        // ideally a service doesn't hold the data just requests it
        private readonly List<Stock> _stocks = new List<Stock>
        {
            new Stock("MSFT", 279.35),
            new Stock("GOOG", 102.11),
        };
    }
    

    We're using a record for the Stock type on purpose, as records are immutable and ensure the purity of objects as well as other features.

    The GetCurrentMarket emits a collection of stocks with updated values every 5 seconds. The IListFeed<T> is a feed tailored for dealing with collections.

  3. Create a class named StockMarketModel.cs replacing its content with the following:

    public partial record StockMarketModel(StockMarketService StockMarketService)
    {
        public IListFeed<Stock> Stocks => ListFeed.AsyncEnumerable(StockMarketService.GetCurrentMarket);
    }
    
Note

Feeds (IFeed<T> and IListFeed<T> for collections) are used as a gateway to asynchronously request data from a service and wrap the result or error if any in metadata to be displayed in the View accordingly. Learn more about list-feeds here.

Tip

Feeds are stateless and are there for when the data from the service is read-only and we're not planning to enable edits to it. MVUX also provides stateful feeds. For that purpose States (IState<T> and <IListState<T> for collections) come handy. Refer to this tutorial to learn more about states.

Data bind the view

The Stocks property on StockMarketModel is an IListFeed<T> where T is Stock. This is similar in concept to an IObservable<IImmutableList<Stock>>, where an IListsFeed<T>> represents a sequence of collections pushed in whenever they become available, signaling the UI about the new data.

Tip

An IListFeed<T> is awaitable, meaning that to get the value of the feed you would execute the following in the model:

StockMarket currentMarket = await this.Stocks;

To make it possible to data bind to feeds, the MVUX analyzers read the StockMarketModel and generate a ViewModel called StockMarketViewModel, which exposes properties that the View can data bind to.

  1. Open the file MainView.xaml and replace anything inside the Page element with the following code:

    <ListView ItemsSource="{Binding Stocks}" SelectionMode="None">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" Spacing="5">
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding Value}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    
  2. Press F7 to navigate to open code-view, and in the constructor, after the line that calls InitializeComponent(), add the following line:

    this.DataContext = new StockMarketViewModel(new StockMarketService());
    
  3. Press F5 to run the app.

  4. The app will display the stock values which will keep updating every 5 seconds.

    Here are 3 screenshots taken consecutively with some delay apart:

    Screenshot showing first stock data Screenshot showing second stock data Screenshot showing third stock data