DevExpress-Examples / maui-list-card

Shows you how to implement a UI element that allows you to preview several items from a lengthy list.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Expandable Cards with Lists

This example shows you how to implement a List Card - a UI element that allows you to preview several items from a lengthy list, access the complete list, and execute custom actions.

Used Controls and Their Properties

A. Header

B. List Items

C. Footer (optional)

A. Header

Anatomy

Users can click the header area to access the complete list.

Behavior

Follow the steps below to handle header clicks and implement navigation to the screen with the complete list of items:

  1. Call the Routing.RegisterRoute method to register the page that contains the complete list of items:

    public partial class App : Application {
        public App() {
            InitializeComponent();
            Routing.RegisterRoute("completeList", typeof(CompleteListPage));
            MainPage = new AppShell();
        }
    }
  2. Specify the DXButton.Command property to define the header click command:

    <dx:DXStackLayout Orientation="Vertical">
        <dx:DXButton Content="{Binding Title}" Command="{Binding NavigateToAllCommand}" ...>
            <dx:DXButton.Content>
                <Grid ColumnDefinitions="*,Auto" HorizontalOptions="Fill" Padding="0">
                    <Label Text="{Binding Title}" .../>
                    <Label Text="{Binding Path=Items.Count, StringFormat='All ({0})'}" .../>
                </Grid>
            </dx:DXButton.Content>
        </dx:DXButton>
    </dx:DXStackLayout>
    namespace CollectionViewWithActionButtons.ViewModels {
        // ...
        public class Card : BindableBase {
            public Card(string title) {
                // ...
                NavigateToAllCommand = new Command(NavigateToAll);
            }
            // ...
            public ICommand NavigateToAllCommand { get; }
            
            public async void NavigateToAll() {
                var navigationParameter = new Dictionary<string, object> { { "Parent", this } };
                await Shell.Current.GoToAsync("completeList", navigationParameter);
            }
        }
    }

    The NavigateToAll method calls the GoToAsync method to open the detail view.

  3. Specify the QueryProperty attribute for the CompleteListViewModel class to pass the clicked header context to the command registered in the previous step:

    namespace CollectionViewWithActionButtons.ViewModels {
        [QueryProperty(nameof(ParentCard), "Parent")]
        internal class CompleteListViewModel : INotifyPropertyChanged {
            private Card parentCard;
            public Card ParentCard {
                get { return parentCard; }
                set {
                    parentCard = value;
                    OnPropertyChanged();
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            void OnPropertyChanged([CallerMemberName] string propertyName = null) {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

B. List Items

This area contains a list of items. You can click on an item to view its details. Click on an button to delete the corresponding item.

Behavior

Follow the steps below to open the CollectionView item detailed information on click:

  1. Specify the DXButton.Command and DXButton.CommandParameter properties to define the item click command. The following code sample uses the FindAncestorBindingContext binding to get the command of the parent object's ItemClick and Hide commands:

    <dxco:DXButton Command="{Binding Source={RelativeSource Mode=FindAncestorBindingContext,
                    AncestorType={x:Type viewModels:Card}}, Path=ItemClickCommand}"
                    CommandParameter="{Binding}">
        <Grid ...>
            <Image Source="{Binding Icon}" .../>
            <Label Text="{Binding Name}" .../>
        </Grid>
    </dxco:DXButton>
    <dxco:DXButton Content="&#x2715;" Command="{Binding Source= {RelativeSource Mode=FindAncestorBindingContext,
                    AncestorType={x:Type viewModels:Card}}, Path=HideCommand}" CommandParameter="{Binding}" .../>
  2. Define the ItemClick and Hide commands in the Card class:

    namespace CollectionViewWithActionButtons.ViewModels {
        public class ViewModel : BindableBase {
            public ViewModel() {
                Cards = DataGenerator.CreateCards();
            }
            public ObservableCollection<Card> Cards { get; set; }
        }
        
        public class Card : BindableBase {
            public Card(string title) {
                Title = title;
                HideCommand = new Command<CardItem>(HideItem);
                ItemClickCommand = new Command<CardItem>(ItemClick);
                // ...
            }
    
            public string Title { get; }
            public ICommand HideCommand { get; }
            public ICommand ItemClickCommand { get; }
            // ...
            public async void ItemClick(CardItem clickedItem) {
                if (clickedItem == null) return;
                await Application.Current.MainPage.DisplayAlert("Item Click", clickedItem.Name, "OK");
            }
            // ...
        }
    
        public class CardItem : BindableBase {
            public string Name { get; set; }
            public string Subtitle { get; set; }
            public DateTime CreatedDate { get; set; }
            public ImageSource Icon { get; set; }
        }
    
        public class BindableBase : INotifyPropertyChanged {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

C. Footer (Optional)

The footer area includes buttons that can initiate list-level actions (such as "Hide All").

Behavior

Buttons within the footer are visible only when the Card.AllowCommonActions property is true. The PrimaryActionName and SecondaryActionName properties define button names.

The following code snippet specifies whether the Security card's footer buttons are visible and defines their names:

public static class DataGenerator {
    public static ObservableCollection<Card> CreateCards() {
        ObservableCollection<Card> cards = new ObservableCollection<Card>();
        cards.Add(new Card("Security") {
            Items = new ObservableCollection<CardItem>() {
                // ...
            },
            PreviewItemsCount = 4,                
            AllowCommonActions = true,
            PrimaryActionName = "Dismiss All",
            SecondaryActionName = "Apply All"
        });
        cards.Add(new Card("Performance") {  
            Items = new ObservableCollection<CardItem>() {
                // ...
            },
            PreviewItemsCount = 3,
        });
        // ...
    }
    // ...
}

Follow the steps below to implement commands that process all CollectionView items within the card:

  1. Specify the DXButton.Command property to define the click commands for both footer buttons.

    <dx:DXStackLayout Orientation="Horizontal" HorizontalOptions="End" x:Name="commonActionsPanel" Padding="20,5,20,0">
        <dx:DXStackLayout.Triggers>
            <DataTrigger TargetType="dx:DXStackLayout" Binding="{Binding AllowCommonActions}" Value="False">
                <Setter Property="IsVisible" Value="False"/>
            </DataTrigger>
        </dx:DXStackLayout.Triggers>
        <dx:DXButton Content="{Binding PrimaryActionName}" Command="{Binding SecondaryActionCommand}" .../>
        <dx:DXButton Content="{Binding SecondaryActionName}" Command="{Binding PrimaryActionCommand}" .../>
    </dx:DXStackLayout>
  2. Define the Card.PrimaryAction and Card.SecondaryAction commands:

    namespace CollectionViewWithActionButtons.ViewModels {
        // ...
        public class Card : BindableBase {
            public Card(string title) {
                // ...
                PrimaryActionCommand = new Command(PrimaryAction);
                SecondaryActionCommand = new Command(SecondaryAction);
            }
            // ...
            public ICommand PrimaryActionCommand { get; }
            public ICommand SecondaryActionCommand { get; }
            public bool AllowCommonActions { get; set; }
            public string PrimaryActionName { get; set; }
            public string SecondaryActionName { get; set; }
            // ...
            }
            // ...
            public async void PrimaryAction() {
                await Application.Current.MainPage.DisplayAlert("Primary Action", "Click", "OK");
            }
            public async void SecondaryAction() {
                await Application.Current.MainPage.DisplayAlert("Secondary Action", "Click", "OK");
            }
            // ...
        }
    }

Files to Look At

Documentation

More Examples

About

Shows you how to implement a UI element that allows you to preview several items from a lengthy list.

License:Other


Languages

Language:C# 100.0%