.netxamlmaui

"In .NET MAUI, when using a CarouselView, the controls within the EmptyView template are disabled by default. How can I enable them?"


I have a CarousalView that display stuff from a collection. When there is nothing in the collection, I want to use the CarouselView EmptyView template to display a button to add an item to the collection. However, there is a transparent box that appears in front of the view and blocks any interact with controls.

I have tried setting InputTransparent, ZIndex and place the empty behind the data template with no effect. do I have to use something besides EmtpyView to achieve my goals?

C#

using System.Collections.ObjectModel;
using System.Windows.Input;
using Microsoft.Maui.Controls;

public class MainViewModel
{
    public ObservableCollection<string> Items { get; set; } = new ObservableCollection<string>();
    public ICommand AddItemCommand { get; set; }

    public MainViewModel()
    {
        AddItemCommand = new Command(AddItem);
    }

    private void AddItem()
    {
        Items.Add($"Item {Items.Count + 1}");
    }
}

Xaml

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourNamespace.MainPage">
    <ContentPage.BindingContext>
        <local:MainViewModel />
    </ContentPage.BindingContext>

    <CarouselView ItemsSource="{Binding Items}">
        <CarouselView.ItemTemplate>
            <DataTemplate>
                <Label Text="{Binding .}" HorizontalOptions="Center" VerticalOptions="Center" />
            </DataTemplate>
        </CarouselView.ItemTemplate>

        <CarouselView.EmptyView>
            <VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center">
                <Label Text="No items available" TextColor="Gray" FontSize="18" />
                <Button Text="Add Item" Command="{Binding AddItemCommand}" />
            </VerticalStackLayout>
        </CarouselView.EmptyView>
    </CarouselView>
</ContentPage>

Solution

  • This issue can be reproduced on Windows Platform. When I searched the MAUI source for CarouselView, I found that,

    // When the empty view is visible, disable hit testing for the ScrollViewer. // This ensures that interactions are directed to the empty view instead of the ScrollViewer. // In the template, the empty view is placed below the ScrollViewer in the visual tree.

    Seems the empty view is placed below the ScrollViewer which is disabled when empty view is visible. So the interaction for the button is disabled. You may raise a feature request on GitHub for this.

    The workaround I can think is to avoid using emptyview and set IsVisible for the CarouselView, e.g, you may separately define the VerticalStackLayout and CarouselView and binds their IsVisible in the ViewModel,

    xaml

        <VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center" IsVisible="{Binding IsStackLayoutVisible}">
            <Label Text="No items available" TextColor="Gray" FontSize="18" />
            <Button Text="Add Item" Command="{Binding AddItemCommand}" />
        </VerticalStackLayout>
    
    
        <CarouselView ItemsSource="{Binding Items}" IsVisible="{Binding IsCarouselViewVisible}"HorizontalScrollBarVisibility="Never" VerticalScrollBarVisibility="Never">
            <CarouselView.ItemTemplate>
                <DataTemplate>
                    <StackLayout>
                        <Label Text="{Binding .}" HorizontalOptions="Center" VerticalOptions="Center" />
                    </StackLayout>
                </DataTemplate>
            </CarouselView.ItemTemplate>
        </CarouselView>
    

    ViewModel, you may control the IsVisible value based on the Items collection,

        [ObservableProperty]
        ObservableCollection<string> items = new ObservableCollection<string>();
        public ICommand AddItemCommand { get; set; }
    
        public MainPageViewModel()
        {
            Items.CollectionChanged += Items_CollectionChanged;
            AddItemCommand = new Command(AddItem);
            if (Items.Count == 0)
            {
                IsHeaderVisible = true;
                IsCarouselViewVisible = false;
            }
        }
    
        private void Items_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (Items.Count==0)
            {
                IsStackLayoutVisible= true;
                IsCarouselViewVisible = false;
            }
            else
            {
                IsStackLayoutVisible= false;
                IsCarouselViewVisible = true;
            }
        }
    

    Hope it helps!