Module 9 - FeedView none and error templates
In the previous module, you've observed how the view doesn't have a special reaction to a service-response that contains no results. In addition, you've also seen how the UI fails to indicate a connection error.
In this module, you'll learn about the power of the FeedView control, and how to use and customize its none (no data) and error templates.
Extract the item template into a separate method
Open the MainPage.cs file and select and cut the entire lambda call contained in the
ItemTemplateextension method of theListViewstarting fromyoutubeVideo => ...(Ctrl+X on Windows). One way to identify the closing parenthesis is by placing the cursor on the opening parenthesis and then checking the keyboard cursor column position (on the bottom-right of the text editor), or by using the arrow to go in a straight line to identify the closing one.In the
MainPageclass, create a static method that returns aUIElementnamedVideoItemTemplateand paste the clipboard contents instead of its parameters parentheses, in the following signature:private static UIElement VideoItemTemplate(YoutubeVideo youtubeVideo)Paste the cut lambda and remove the old
youtubeVideoparameter which is now duplicated.Add a closing semicolon (
;) to terminate this method.Here's the final result:
VideoItemTemplatemethod (collapsed for brevity).private static UIElement VideoItemTemplate(YoutubeVideo youtubeVideo) => new CardContentControl() .Margin(0, 0, 0, 8) .Style(StaticResource.Get<Style>("ElevatedCardContentControlStyle")) .Content ( new AutoLayout() .Background(Theme.Brushes.Surface.Default) .CornerRadius(12) .PrimaryAxisAlignment(AutoLayoutAlignment.Center) .Children ( new AutoLayout() .Background(Theme.Brushes.Surface.Default) .CornerRadius(12) .Padding(8, 8, 8, 0) .MaxHeight(288) .MaxWidth(456) .AutoLayout(counterAlignment: AutoLayoutAlignment.Center) .Children ( new Border() .Height(204.75) .CornerRadius(6) .Child ( new Image() .Source(() => youtubeVideo.Details.Snippet?.Thumbnails?.Medium?.Url!) .Stretch(Stretch.UniformToFill) ), new AutoLayout() .Spacing(8) .Orientation(Orientation.Horizontal) .Padding(0, 8) .Children ( new Border() .Width(60) .Height(60) .CornerRadius(6) .AutoLayout(counterAlignment: AutoLayoutAlignment.Center) .Child ( new Image() .Source(() => youtubeVideo.Channel.Snippet?.Thumbnails?.Medium?.Url!) .Stretch(Stretch.UniformToFill) ), new AutoLayout() .PrimaryAxisAlignment(AutoLayoutAlignment.Center) .AutoLayout(primaryAlignment: AutoLayoutPrimaryAlignment.Stretch) .Children ( new TextBlock() .Text(() => youtubeVideo.Channel.Snippet?.Title) .Height(22) .Foreground(Theme.Brushes.OnSurface.Default) .Style(Theme.TextBlock.Styles.TitleMedium), new TextBlock() .Text(() => youtubeVideo.Details.Snippet?.Title) .Height(16) .Foreground(Theme.Brushes.OnSurface.Medium) ), new Button() .Foreground(Theme.Brushes.OnSurface.Variant.Default) .Style(Theme.Button.Styles.Icon) .AutoLayout(counterAlignment: AutoLayoutAlignment.Center) .Content ( new PathIcon() .Data(StaticResource.Get<Geometry>("Icon_Chevron_Right")) .Foreground(Theme.Brushes.OnSurface.Variant.Default) ) ) ) ) );Replace the
ListView'sItemTemplateextension method with the following:.ItemTemplate<YoutubeVideo>(VideoItemTemplate)
Add a FeedView to the UI and customize the NoneTemplate
Add FeedView
The FeedView control is shipped as part of the MVUX and is tailored to work with feeds and states.
It reacts visually to the current state of the data and its underlying request. Here's a brief overview of the templates it currently supports:
ValueTemplate- used when there are ordinary data resultsNoneTemplate- used when there was no data foundErrorTemplate- used when an error occurs while requesting dataProgressTemplate- used when the underlying feed or state is busy loading dataUndefinedTemplate- used when the control initializes, before the request is sent
Tip
To learn more about the FeedView, head over to its docs page.
Let's add a FeedView to our UI. We'll start with the ValueTemplate first.
Open the file MainPage.cs and wrap the search results
ListViewin aFeedView:new FeedView() .AutoLayout(primaryAlignment: AutoLayoutPrimaryAlignment.Stretch) .VerticalAlignment(VerticalAlignment.Stretch) .VerticalContentAlignment(VerticalAlignment.Stretch) .Source(() => vm.VideoSearchResults) .ValueTemplate<FeedViewState>(feedViewState => new ListView() ... )Feel free to touch up the code and indent it by selecting the code and pressing Tab or Shift+Tab to indent/unindent code in Visual Studio.
Change the
ItemsSourceproperty of theListViewto theDataproperty of theFeedViewStateas follows:... new ListView() - .ItemsSource(b => b.Binding("VideoSearchResults")) + .ItemsSource(() => feedViewState.Data) ... .ItemTemplate(VideoItemTemplate) ...The
FeedViewserves the data via theFeedViewStatewrapper class to the template, the actual data is accessed via the wrapper'sDataproperty.
Run the app [optional]
The FeedView's error template defaults to *An error occurred' text message. If you run the app, switch flight mode on, and search YouTube, that message will display:

Customize the NoneTemplate
Add the following Shapes namespace, as well as the Path alias to the header of MainPage.cs, so that there are no ambiguations with System.IO.Path, as there are Path elements contained in the templates you are about to introduce to the project.
using Microsoft.UI.Xaml.Shapes;
using Path = Microsoft.UI.Xaml.Shapes.Path;
Open Figma and select the 1.3 No search results state screen.
Open the Uno Platform plugin (Ctrl+Alt+P), and navigate to the Export tab.
Click the Refresh button.

In the generated C# code, skip the navigation bar and the search box parts, then select and copy the
AutoLayoutthat follows, with all its descendants.Add a private static method named
VideoNoneTemplatereturningUIElementinto theMainPageclass.Paste the content copied from Figma as the return value of the method.
private static UIElement VideoNoneTemplate() => /* copied content */Append a semicolon (
;) to the end of the method to terminate it.
Add the following setting to the FeedView:
new FeedView()
...
+ .NoneTemplate(VideoNoneTemplate)
.ValueTemplate...
Run the app
When you run the app next and delete the search term, you'll see how the FeedView switches to the NoneTemplate you've just set up when there is no data:

Customize the ErrorTemplate
Import template
Open Figma and select the 1.2 Error first loading error screen.
Open the Uno Platform plugin (Ctrl+Alt+P), and navigate to the Export tab.
Click the Refresh button.

From the generated C#, skip the navigation bar and the search box parts, then select and copy the
AutoLayoutthat follows, with all its descendants.Add a private static method named
VideoErrorTemplatereturningUIElementinto theMainPageclass:Paste the content copied from Figma as the return value of the method.
private static UIElement VideoErrorTemplate() => /* copied content */Append a semicolon (
;) to the end of the method to terminate it.
Append the following property setting to the FeedView:
new FeedView()
...
.ErrorTemplate(VideoErrorTemplate)
...
Run the app
Run the app. Search results for the term Uno Platform will be loaded from YouTube.
Disable the device's network (flight mode).
Perform a new search by changing the search term.
Observe how the error template is displayed.
Restore the internet connection and return to the result.
Click one of the search results, and you'll notice that the video on the video page doesn't play. In the upcoming module, you'll add a media player control to the app, which will play the videos.
