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
ItemTemplate
extension method of theListView
starting 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
MainPage
class, create a static method that returns aUIElement
namedVideoItemTemplate
and 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
youtubeVideo
parameter which is now duplicated.Add a closing semicolon (
;
) to terminate this method.Here's the final result:
VideoItemTemplate
method (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
'sItemTemplate
extension 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
ListView
in 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
ItemsSource
property of theListView
to theData
property of theFeedViewState
as follows:... new ListView() - .ItemsSource(b => b.Binding("VideoSearchResults")) + .ItemsSource(() => feedViewState.Data) ... .ItemTemplate(VideoItemTemplate) ...
The
FeedView
serves the data via theFeedViewState
wrapper class to the template, the actual data is accessed via the wrapper'sData
property.
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
AutoLayout
that follows, with all its descendants.Add a private static method named
VideoNoneTemplate
returningUIElement
into theMainPage
class.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
AutoLayout
that follows, with all its descendants.Add a private static method named
VideoErrorTemplate
returningUIElement
into theMainPage
class: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.