
Syncfusion Maui Toolkit Cards
- 1 installs
- 39 repo stars
- Updated June 19, 2026
- syncfusion/maui-toolkit-ui-components-skills
Implement stacked, swipeable Syncfusion SfCardLayout and SfCardView UIs in.NET MAUI apps.
About
Syncfusion MAUI Toolkit Cards documents how to build Tinder-style stacked card interfaces with SfCardLayout and SfCardView in.NET MAUI. mobile developers use it when onboarding flows, discovery decks, or actionable item stacks need swipe-to-dismiss or swipe-to-advance without hand-rolling gesture math. The skill walks ShowSwipedCard for edge peek of dismissed cards, VisibleIndex to jump programmatically, and SwipeDirection to constrain UX. XAML examples tie properties to HeightRequest layouts and labeled card content so agents generate valid Syncfusion markup. It is reference-shaped component documentation rather than a full app scaffold—pair it with your navigation and view models. Expect intermediate familiarity with MAUI namespaces and Syncfusion cards package installation before invoking the skill in an agent session.
- SfCardLayout stacks SfCardView children with one visible card and swipe navigation
- Four swipe directions: Left, Right, Top, Bottom
- ShowSwipedCard, VisibleIndex, and SwipeDirection properties for programmatic and edge display control
- Documents common scenarios, managing multiple cards, and best practices
- Hard rule: SfCardLayout only accepts SfCardView as direct children
Syncfusion Maui Toolkit Cards by the numbers
- 1 all-time installs (skills.sh)
- Ranked #959 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Jul 7, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/maui-toolkit-ui-components-skills --skill syncfusion-maui-toolkit-cardsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 39 |
| Last updated | June 19, 2026 |
| Repository | syncfusion/maui-toolkit-ui-components-skills ↗ |
What it does
Implement stacked, swipeable Syncfusion SfCardLayout and SfCardView UIs in.NET MAUI apps.
Files
Implementing .NET MAUI Cards (SfCards)
The Syncfusion .NET MAUI Cards control, which provides both dismissible single card views (SfCardView) and swipeable card stacks (SfCardLayout). This skill covers installation, card creation, swipe gestures, customization, data binding, events, and modern visual effects.
When to Use This Skill
Use this skill when the user needs to:
- Create dismissible card views - Single cards that can be swiped away (left/right)
- Build card stacks - Multiple stacked cards with swipe navigation
- Implement swipe gestures - Cards that respond to swipe in four directions (left, right, top, bottom)
- Display card-based UI - Visual card containers for content organization
- Add interactive cards - Cards with tap events, dismiss events, and state management
- Bind data to cards - Dynamically generate cards from data collections using BindableLayout
- Customize card appearance - Borders, corners, indicators, colors.
- Handle card events - Tapped, dismissing, dismissed, index changing events
This skill is specifically for Syncfusion's .NET MAUI Cards control (SfCardView and SfCardLayout), not generic card layouts or other card libraries.
Component Overview
The Syncfusion .NET MAUI Cards control provides two main components:
1. SfCardView - A single card that can optionally be dismissed by swiping 2. SfCardLayout - A container for stacking multiple SfCardView items with swipe navigation
Key Capabilities:
- Swipe-to-dismiss functionality
- Multi-directional swipe support (left, right, top, bottom)
- Visual customization (borders, corners, indicators)
- Programmatic card dismissal
- Data binding with BindableLayout
- Comprehensive event handling
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
Read this reference when the user needs to:
- Install the Syncfusion.Maui.Toolkit NuGet package
- Register Syncfusion handlers in MauiProgram.cs (ConfigureSyncfusionToolkit)
- Create their first SfCardView
- Understand basic XAML and C# implementation patterns
Card View Features
📄 Read: references/card-views.md
Read this reference when the user works with single cards and needs:
- SfCardView component overview and usage
- SwipeToDismiss property for swipe-away functionality
- IsDismissed property for programmatic dismissal
- FadeOutOnSwiping visual effect
- Single card implementation patterns
- Standalone card scenarios
Card Layout Features
📄 Read: references/card-layouts.md
Read this reference when the user needs card stacks with:
- SfCardLayout component (multiple stacked cards)
- ShowSwipedCard property for edge display
- VisibleIndex property for card navigation
- SwipeDirection configuration (Left, Right, Top, Bottom)
- Multiple card management
- Swipe gesture navigation between cards
Customization and Styling
📄 Read: references/customization.md
Read this reference when the user wants to customize:
- BorderColor, BorderWidth, CornerRadius properties
- Background colors and gradients
- Indicator customization (color, thickness, position)
- FadeOutOnSwiping effect
- Advanced visual styling
- Custom card designs and themes
Data Binding with BindableLayout
📄 Read: references/data-binding.md
Read this reference when the user needs to:
- Generate cards dynamically from data collections
- Use BindableLayout with SfCardLayout
- Set up ViewModels and data sources
- Configure ItemsSource and ItemTemplate
- Create data-driven card interfaces
- Bind card properties to data models
Events and Interactions
📄 Read: references/events.md
Read this reference when the user needs to handle:
- Tapped event (card tap detection)
- VisibleIndexChanging event (before card changes, with Cancel support)
- VisibleIndexChanged event (after card changes)
- Dismissing event (before dismiss, with Cancel support)
- Dismissed event (after dismiss completes)
- Event handler implementation and scenarios
Card Layout Features
Table of Contents
- Overview
- ShowSwipedCard Property
- VisibleIndex Property
- SwipeDirection Property
- Managing Multiple Cards
- Common Scenarios
- Best Practices
Overview
SfCardLayout is a container that displays multiple SfCardView items in a stacked layout. Only one card is visible at a time, and users can swipe to navigate between cards. This creates an interactive, Tinder-style card interface.
Key Features:
- Stack multiple cards with only one visible
- Swipe navigation in four directions (Left, Right, Top, Bottom)
- Show swiped cards at layout edges
- Programmatic control over visible card
- Full event support for card changes
Important: SfCardLayout only accepts SfCardView as direct children.
ShowSwipedCard Property
The ShowSwipedCard property determines whether swiped cards are displayed at the edge of the card layout after being dismissed.
Type: bool Default: false
Basic Usage
XAML:
<cards:SfCardLayout ShowSwipedCard="True" HeightRequest="400">
<cards:SfCardView>
<Label Text="Card 1" BackgroundColor="Cyan"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 2" BackgroundColor="Yellow"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 3" BackgroundColor="Orange"/>
</cards:SfCardView>
</cards:SfCardLayout>C#:
SfCardLayout cardLayout = new SfCardLayout
{
ShowSwipedCard = true,
HeightRequest = 400
};
cardLayout.Children.Add(new SfCardView
{
Content = new Label { Text = "Card 1", BackgroundColor = Colors.Cyan }
});
cardLayout.Children.Add(new SfCardView
{
Content = new Label { Text = "Card 2", BackgroundColor = Colors.Yellow }
});
cardLayout.Children.Add(new SfCardView
{
Content = new Label { Text = "Card 3", BackgroundColor = Colors.Orange }
});Visual Effect
- ShowSwipedCard = false: Swiped cards disappear completely
- ShowSwipedCard = true: Swiped cards remain visible at the edge, creating a stack effect
When to Use
Enable ShowSwipedCard when:
- Users need visual context of how many cards remain
- Creating a "deck of cards" visual metaphor
- Building browsing interfaces where users can see discarded items
Disable ShowSwipedCard when:
- You want a cleaner, focused interface
- Creating a "one at a time" flow
- Performance is critical with many cards
VisibleIndex Property
The VisibleIndex property gets or sets the index of the card that should be displayed at the front of the card layout.
Type: int Default: 0
Basic Usage
XAML:
<cards:SfCardLayout VisibleIndex="1" HeightRequest="400">
<cards:SfCardView>
<Label Text="Card 0"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 1 - Visible on start"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 2"/>
</cards:SfCardView>
</cards:SfCardLayout>C#:
SfCardLayout cardLayout = new SfCardLayout
{
VisibleIndex = 1, // Start with second card
HeightRequest = 400
};
// Add cards...Programmatic Navigation
// Navigate to specific card
cardLayout.VisibleIndex = 2; // Show third card
// Navigate to next card
cardLayout.VisibleIndex++;
// Navigate to previous card
cardLayout.VisibleIndex--;
// Navigate to first card
cardLayout.VisibleIndex = 0;
// Navigate to last card
cardLayout.VisibleIndex = cardLayout.Children.Count - 1;Example: Navigation Buttons
var cardLayout = new SfCardLayout { HeightRequest = 400 };
// Add cards
for (int i = 0; i < 5; i++)
{
cardLayout.Children.Add(new SfCardView
{
Content = new Label
{
Text = $"Card {i + 1}",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
FontSize = 24
}
});
}
// Navigation controls
var buttonStack = new HorizontalStackLayout
{
HorizontalOptions = LayoutOptions.Center,
Spacing = 20
};
var prevButton = new Button { Text = "Previous" };
prevButton.Clicked += (s, e) =>
{
if (cardLayout.VisibleIndex > 0)
cardLayout.VisibleIndex--;
};
var nextButton = new Button { Text = "Next" };
nextButton.Clicked += (s, e) =>
{
if (cardLayout.VisibleIndex < cardLayout.Children.Count - 1)
cardLayout.VisibleIndex++;
};
buttonStack.Children.Add(prevButton);
buttonStack.Children.Add(nextButton);Getting Current Index
int currentIndex = cardLayout.VisibleIndex;
Console.WriteLine($"Currently showing card {currentIndex}");
// Get current card
if (cardLayout.VisibleIndex >= 0 &&
cardLayout.VisibleIndex < cardLayout.Children.Count)
{
var currentCard = cardLayout.Children[cardLayout.VisibleIndex] as SfCardView;
}SwipeDirection Property
The SwipeDirection property specifies the direction(s) in which cards can be swiped. This controls the swipe gesture behavior.
Type: CardSwipeDirection (enum with flags support) Default: CardSwipeDirection.Right
Available Values:
CardSwipeDirection.LeftCardSwipeDirection.RightCardSwipeDirection.TopCardSwipeDirection.Bottom
Single Direction Examples
Swipe Left Only:
<cards:SfCardLayout SwipeDirection="Left" HeightRequest="400">
<!-- Cards -->
</cards:SfCardLayout>SfCardLayout cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Left,
HeightRequest = 400
};Swipe Right Only:
cardLayout.SwipeDirection = CardSwipeDirection.Right;Swipe Up (Top):
cardLayout.SwipeDirection = CardSwipeDirection.Top;Swipe Down (Bottom):
cardLayout.SwipeDirection = CardSwipeDirection.Bottom;Direction-Based Actions Example
var cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Left,
ShowSwipedCard = true,
HeightRequest = 500
};
// Track swipe directions
cardLayout.VisibleIndexChanged += (s, e) =>
{
// Determine swipe direction based on index change
if (e.NewIndex > e.OldIndex)
{
Console.WriteLine("Swiped left (next card)");
// Handle "reject" action
}
else if (e.NewIndex < e.OldIndex)
{
Console.WriteLine("Swiped right (previous card)");
// Handle "accept" action
}
};Use Cases by Direction
Left/Right (Horizontal):
- Dating apps (swipe left to pass, right to like)
- Product browsing
- Image galleries
- Content feeds
Top/Bottom (Vertical):
- Story viewers
- Vertical content feeds
- News articles
- Social media posts
Managing Multiple Cards
Adding Cards Dynamically
SfCardLayout cardLayout = new SfCardLayout();
// Add cards programmatically
for (int i = 1; i <= 10; i++)
{
var card = new SfCardView
{
CornerRadius = 15,
Margin = 5,
Content = new Grid
{
BackgroundColor = GetRandomColor(),
Children =
{
new Label
{
Text = $"Card {i}",
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
FontSize = 28,
TextColor = Colors.White
}
}
}
};
cardLayout.Children.Add(card);
}Removing Cards
// Remove specific card
cardLayout.Children.RemoveAt(index);
// Remove current visible card
if (cardLayout.VisibleIndex >= 0 &&
cardLayout.VisibleIndex < cardLayout.Children.Count)
{
cardLayout.Children.RemoveAt(cardLayout.VisibleIndex);
}
// Clear all cards
cardLayout.Children.Clear();Inserting Cards
// Insert at specific position
var newCard = new SfCardView { Content = new Label { Text = "New Card" } };
cardLayout.Children.Insert(2, newCard);
// Add to end
cardLayout.Children.Add(newCard);Getting Card Count
int totalCards = cardLayout.Children.Count;
int remainingCards = cardLayout.Children.Count - cardLayout.VisibleIndex;Common Scenarios
Scenario 1: Dating App Style Interface
public class ProfileCardLayout : ContentView
{
private SfCardLayout cardLayout;
private List<Profile> profiles;
public ProfileCardLayout(List<Profile> profiles)
{
this.profiles = profiles;
cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Right,
ShowSwipedCard = true,
HeightRequest = 500,
WidthRequest = 350,
BackgroundColor = Colors.Transparent
};
// Populate cards
foreach (var profile in profiles)
{
cardLayout.Children.Add(CreateProfileCard(profile));
}
// Handle swipes
cardLayout.VisibleIndexChanged += OnCardSwiped;
Content = cardLayout;
}
private SfCardView CreateProfileCard(Profile profile)
{
return new SfCardView
{
CornerRadius = 20,
Content = new Grid
{
Children =
{
new Image { Source = profile.PhotoUrl, Aspect = Aspect.AspectFill },
new VerticalStackLayout
{
VerticalOptions = LayoutOptions.End,
Padding = 20,
BackgroundColor = Colors.Black.WithAlpha(0.5f),
Children =
{
new Label
{
Text = profile.Name,
FontSize = 24,
TextColor = Colors.White,
FontAttributes = FontAttributes.Bold
},
new Label
{
Text = $"{profile.Age}, {profile.Location}",
TextColor = Colors.White
}
}
}
}
}
};
}
private void OnCardSwiped(object sender, CardVisibleIndexChangedEventArgs e)
{
if (e.NewIndex > e.OldIndex)
{
// Swiped left - Pass
ProcessSwipe(profiles[e.OldIndex], SwipeAction.Pass);
}
else
{
// Swiped right - Like
ProcessSwipe(profiles[e.OldIndex], SwipeAction.Like);
}
}
}Scenario 2: Product Showcase
public SfCardLayout CreateProductShowcase(List<Product> products)
{
var cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Left,
ShowSwipedCard = false,
HeightRequest = 600,
VisibleIndex = 0
};
foreach (var product in products)
{
var card = new SfCardView
{
CornerRadius = 15,
BorderWidth = 1,
BorderColor = Colors.LightGray,
Content = new Grid
{
RowDefinitions =
{
new RowDefinition { Height = 300 },
new RowDefinition { Height = GridLength.Auto }
},
Children =
{
new Image
{
Source = product.ImageUrl,
Aspect = Aspect.AspectFill
}.Row(0),
new VerticalStackLayout
{
Padding = 15,
Children =
{
new Label
{
Text = product.Name,
FontSize = 20,
FontAttributes = FontAttributes.Bold
},
new Label
{
Text = product.Description,
FontSize = 14,
TextColor = Colors.Gray
},
new Label
{
Text = $"${product.Price:F2}",
FontSize = 24,
TextColor = Colors.Green,
FontAttributes = FontAttributes.Bold
}
}
}.Row(1)
}
}
};
cardLayout.Children.Add(card);
}
return cardLayout;
}Scenario 3: Onboarding Flow
public class OnboardingCards : ContentView
{
private SfCardLayout cardLayout;
private Button nextButton;
public OnboardingCards()
{
cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Left,
VisibleIndex = 0,
HeightRequest = 500
};
// Add onboarding screens
cardLayout.Children.Add(CreateOnboardingCard(
"Welcome",
"Welcome to our app!",
"welcome_icon.png"
));
cardLayout.Children.Add(CreateOnboardingCard(
"Features",
"Discover amazing features",
"features_icon.png"
));
cardLayout.Children.Add(CreateOnboardingCard(
"Get Started",
"Ready to begin?",
"start_icon.png"
));
// Next button
nextButton = new Button
{
Text = "Next",
HorizontalOptions = LayoutOptions.Center
};
nextButton.Clicked += (s, e) =>
{
if (cardLayout.VisibleIndex < cardLayout.Children.Count - 1)
{
cardLayout.VisibleIndex++;
}
else
{
// Complete onboarding
CompleteOnboarding();
}
// Update button text on last card
nextButton.Text = cardLayout.VisibleIndex == cardLayout.Children.Count - 1
? "Get Started"
: "Next";
};
Content = new VerticalStackLayout
{
Children = { cardLayout, nextButton }
};
}
private SfCardView CreateOnboardingCard(string title, string description, string icon)
{
return new SfCardView
{
Content = new VerticalStackLayout
{
Spacing = 20,
Padding = 30,
Children =
{
new Image { Source = icon, HeightRequest = 150 },
new Label
{
Text = title,
FontSize = 28,
FontAttributes = FontAttributes.Bold,
HorizontalTextAlignment = TextAlignment.Center
},
new Label
{
Text = description,
FontSize = 16,
HorizontalTextAlignment = TextAlignment.Center,
TextColor = Colors.Gray
}
}
}
};
}
}Best Practices
1. Set Appropriate Height
Always set HeightRequest for proper card display:
cardLayout.HeightRequest = 500; // Recommended minimum: 300-6002. Limit Card Count
For performance, avoid adding hundreds of cards at once. Consider:
- Lazy loading
- Pagination
- Virtual scrolling for large datasets
3. Use ShowSwipedCard Wisely
Enable for better user context, disable for cleaner UI:
cardLayout.ShowSwipedCard = true; // Better for browsing
cardLayout.ShowSwipedCard = false; // Better for focused tasks4. Handle Edge Cases
// Check bounds before changing index
if (cardLayout.VisibleIndex >= 0 &&
cardLayout.VisibleIndex < cardLayout.Children.Count)
{
// Safe to access
}5. Combine with Events
Always handle VisibleIndexChanged for tracking and analytics:
cardLayout.VisibleIndexChanged += (s, e) =>
{
LogCardView(e.NewIndex);
UpdateUI();
};Card View Features
Table of Contents
- Overview
- SwipeToDismiss Property
- IsDismissed Property
- FadeOutOnSwiping Property
- Common Scenarios
- Best Practices
- Limitations
Overview
SfCardView represents a single card UI element that can display any content. It provides swipe-to-dismiss functionality, programmatic dismissal control, and visual effects. This component is ideal for notifications, alerts, removable items, or any dismissible content.
Key Features:
- Swipe-to-dismiss in left/right directions
- Programmatic control over dismissed state
- Fade effect during swiping
- Full content customization
- Event handling for dismissal
SwipeToDismiss Property
The SwipeToDismiss property enables or disables the swiping feature, allowing users to dismiss the card by swiping left or right.
Type: bool Default: false
Basic Usage
XAML:
<cards:SfCardView SwipeToDismiss="True">
<Label Text="SfCardView"
Background="MediumPurple"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</cards:SfCardView>C#:
SfCardView cardView = new SfCardView
{
SwipeToDismiss = true,
Content = new Label
{
Text = "SfCardView",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
BackgroundColor = Colors.MediumPurple
}
};How It Works
1. User swipes the card left or right 2. Card follows the finger/pointer 3. If swipe distance exceeds threshold, card dismisses 4. If swipe is released before threshold, card returns to position 5. Dismissing event fires (can be canceled) 6. Card animates out of view 7. Dismissed event fires
Example: Dismissible Notification
var notificationCard = new SfCardView
{
SwipeToDismiss = true,
Padding = 15,
CornerRadius = 8,
BackgroundColor = Colors.White,
Content = new VerticalStackLayout
{
Children =
{
new Label
{
Text = "New Message",
FontSize = 18,
FontAttributes = FontAttributes.Bold
},
new Label
{
Text = "You have received a new message from John",
FontSize = 14,
TextColor = Colors.Gray
}
}
}
};
// Handle dismissed event
notificationCard.Dismissed += (s, e) =>
{
Console.WriteLine($"Notification dismissed in direction: {e.DismissDirection}");
// Remove from UI, update database, etc.
};IsDismissed Property
The IsDismissed property allows you to get or set the dismissed state of the card programmatically. This is useful for dismissing cards based on business logic rather than user gestures.
Type: bool Default: false
Basic Usage
XAML:
<cards:SfCardView x:Name="myCard" IsDismissed="False">
<Label Text="SfCardView"/>
</cards:SfCardView>
<Button Text="Dismiss Card" Clicked="OnDismissClicked"/>C# (Code-behind):
private void OnDismissClicked(object sender, EventArgs e)
{
myCard.IsDismissed = true;
}Programmatic Dismissal Example
SfCardView cardView = new SfCardView
{
IsDismissed = false,
Content = new Label { Text = "Auto-dismiss in 3 seconds" }
};
// Dismiss after 3 seconds
Device.StartTimer(TimeSpan.FromSeconds(3), () =>
{
cardView.IsDismissed = true;
return false; // Stop timer
});Checking Dismissed State
if (cardView.IsDismissed)
{
Console.WriteLine("Card is currently dismissed");
}
else
{
Console.WriteLine("Card is visible");
}Restoring a Dismissed Card
// Re-show a dismissed card
cardView.IsDismissed = false;FadeOutOnSwiping Property
The FadeOutOnSwiping property enables a fade effect as the card is swiped, creating a smooth visual transition during dismissal.
Type: bool Default: false
IMPORTANT: This property only works for standalone SfCardView. It does NOT work when SfCardView is a child of SfCardLayout.
Basic Usage
XAML:
<cards:SfCardView FadeOutOnSwiping="True" SwipeToDismiss="True">
<Label Text="Swipe me - I fade out!"
Background="LightBlue"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</cards:SfCardView>C#:
SfCardView cardView = new SfCardView
{
FadeOutOnSwiping = true,
SwipeToDismiss = true,
Content = new Label
{
Text = "Swipe me - I fade out!",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
BackgroundColor = Colors.LightBlue
}
};Visual Effect
- Without FadeOutOnSwiping: Card moves horizontally at full opacity until dismissed
- With FadeOutOnSwiping: Card gradually becomes transparent as it moves, creating a smooth fade-out effect
Example: Elegant Dismissal
var elegantCard = new SfCardView
{
SwipeToDismiss = true,
FadeOutOnSwiping = true,
CornerRadius = 12,
BorderWidth = 0,
BackgroundColor = Colors.White,
Shadow = new Shadow
{
Brush = Colors.Black,
Opacity = 0.3f,
Radius = 10,
Offset = new Point(0, 2)
},
Content = new Grid
{
Padding = 20,
Children =
{
new Label
{
Text = "Elegant Card",
FontSize = 20,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
}
}
}
};Common Scenarios
Scenario 1: Dismissible Alert
public class DismissibleAlert : SfCardView
{
public DismissibleAlert(string message, Color backgroundColor)
{
SwipeToDismiss = true;
FadeOutOnSwiping = true;
CornerRadius = 8;
Margin = 10;
BackgroundColor = backgroundColor;
Content = new Label
{
Text = message,
Padding = 15,
TextColor = Colors.White,
FontAttributes = FontAttributes.Bold
};
// Auto-dismiss after 5 seconds
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
IsDismissed = true;
return false;
});
}
}
// Usage
var alert = new DismissibleAlert("Operation successful!", Colors.Green);Scenario 2: Inbox Message Card
public SfCardView CreateMessageCard(string sender, string subject, string preview)
{
var card = new SfCardView
{
SwipeToDismiss = true,
Padding = 15,
Margin = new Thickness(10, 5),
CornerRadius = 10,
BorderWidth = 1,
BorderColor = Colors.LightGray,
BackgroundColor = Colors.White
};
var layout = new VerticalStackLayout
{
Spacing = 5,
Children =
{
new Label
{
Text = sender,
FontSize = 16,
FontAttributes = FontAttributes.Bold
},
new Label
{
Text = subject,
FontSize = 14
},
new Label
{
Text = preview,
FontSize = 12,
TextColor = Colors.Gray,
MaxLines = 2,
LineBreakMode = LineBreakMode.TailTruncation
}
}
};
card.Content = layout;
// Handle dismissal
card.Dismissed += (s, e) =>
{
// Archive or delete message
ArchiveMessage(subject);
};
return card;
}Scenario 3: Todo Item Card
public SfCardView CreateTodoCard(TodoItem item)
{
var card = new SfCardView
{
SwipeToDismiss = true,
FadeOutOnSwiping = true,
CornerRadius = 8,
Margin = new Thickness(15, 5),
BackgroundColor = item.IsCompleted ? Colors.LightGray : Colors.White
};
var grid = new Grid
{
Padding = 15,
ColumnDefinitions =
{
new ColumnDefinition { Width = GridLength.Star },
new ColumnDefinition { Width = GridLength.Auto }
}
};
grid.Add(new Label
{
Text = item.Title,
VerticalOptions = LayoutOptions.Center,
TextDecorations = item.IsCompleted ? TextDecorations.Strikethrough : TextDecorations.None
}, 0, 0);
grid.Add(new CheckBox
{
IsChecked = item.IsCompleted,
VerticalOptions = LayoutOptions.Center
}, 1, 0);
card.Content = grid;
// When dismissed, mark as completed
card.Dismissed += (s, e) =>
{
item.IsCompleted = true;
SaveTodoItem(item);
};
return card;
}Best Practices
1. Use SwipeToDismiss for Temporary Content
Perfect for:
- Notifications
- Alerts
- Temporary messages
- Dismissible list items
2. Combine with Events
Always handle the Dismissed event to clean up or update state:
cardView.Dismissed += (s, e) =>
{
// Update database
// Remove from collection
// Log analytics
};3. Provide Visual Feedback
Use FadeOutOnSwiping for smooth, polished dismissal animations:
cardView.FadeOutOnSwiping = true; // Better UX4. Set Appropriate Sizing
Give cards enough space to be swipeable:
cardView.HeightRequest = 100; // Minimum recommended
cardView.WidthRequest = 300;5. Consider Auto-Dismiss
For time-sensitive notifications, combine swipe-to-dismiss with auto-dismiss:
var card = new SfCardView { SwipeToDismiss = true };
// Auto-dismiss after timeout
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
card.IsDismissed = true;
return false;
});Limitations
1. SwipeToDismiss in CardLayout
Issue: SwipeToDismiss does NOT work when SfCardView is a child of SfCardLayout.
Reason: In CardLayout, swipe gestures are used for card navigation between stacked cards.
Solution: Use SwipeToDismiss only for standalone cards.
2. FadeOutOnSwiping in CardLayout
Issue: FadeOutOnSwiping does NOT work when SfCardView is a child of SfCardLayout.
Solution: Use FadeOutOnSwiping only for standalone cards.
3. Swipe Direction
Limitation: Swipe-to-dismiss only supports left and right directions. Top and bottom swipes are not supported for dismissal.
Performance Tips
1. Dispose properly: When dismissing cards, ensure proper cleanup 2. Use IsDismissed for batch operations: More efficient than animating multiple dismissals 3. Limit card count: For many dismissible items, consider virtualization patterns
Customization and Styling
Table of Contents
- Overview
- Border Customization
- Corner Radius
- Background and Colors
- Indicator Customization
- Shadows and Elevation
- Advanced Styling Examples
- Best Practices
Overview
The .NET MAUI Cards control provides extensive customization options for creating visually appealing and distinctive card designs. You can customize borders, corners, colors, indicators, and more to match your application's design language.
Border Customization
BorderColor Property
Sets the border color of the card view.
Type: Color Default: Transparent
XAML:
<cards:SfCardView BorderColor="Blue" BorderWidth="2">
<Label Text="Card with blue border"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
BorderColor = Colors.Blue,
BorderWidth = 2,
Content = new Label { Text = "Card with blue border" }
};BorderWidth Property
Sets the thickness of the card's border.
Type: double Default: 0
XAML:
<cards:SfCardView BorderColor="Gray" BorderWidth="3">
<Label Text="Thick border card"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
BorderColor = Colors.Gray,
BorderWidth = 3,
Content = new Label { Text = "Thick border card" }
};Border Examples
Subtle Border:
var card = new SfCardView
{
BorderColor = Colors.LightGray,
BorderWidth = 1,
BackgroundColor = Colors.White
};Accent Border:
var card = new SfCardView
{
BorderColor = Colors.Blue,
BorderWidth = 2,
BackgroundColor = Colors.White
};No Border (Flat Design):
var card = new SfCardView
{
BorderWidth = 0, // No border
BackgroundColor = Colors.White
};Corner Radius
The CornerRadius property allows you to create rounded corners on cards.
Type: CornerRadius Default: 0 (sharp corners)
Uniform Corners
XAML:
<cards:SfCardView CornerRadius="15">
<Label Text="Rounded card"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
CornerRadius = 15,
Content = new Label { Text = "Rounded card" }
};Individual Corner Customization
XAML:
<cards:SfCardView>
<cards:SfCardView.CornerRadius>
<CornerRadius TopLeft="20" TopRight="20" BottomLeft="5" BottomRight="5"/>
</cards:SfCardView.CornerRadius>
<Label Text="Custom corners"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
CornerRadius = new CornerRadius(20, 20, 5, 5), // TL, TR, BL, BR
Content = new Label { Text = "Custom corners" }
};Corner Radius Guidelines
- 0-5: Subtle rounding
- 8-12: Standard modern design
- 15-20: Prominent rounded look
- 25+: Pill-shaped or circular
Background and Colors
Solid Colors
XAML:
<cards:SfCardView BackgroundColor="PeachPuff">
<Label Text="Colored card"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
BackgroundColor = Colors.PeachPuff,
Content = new Label { Text = "Colored card" }
};Gradient Backgrounds
XAML:
<cards:SfCardView>
<cards:SfCardView.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#6a11cb" Offset="0.0"/>
<GradientStop Color="#2575fc" Offset="1.0"/>
</LinearGradientBrush>
</cards:SfCardView.Background>
<Label Text="Gradient card" TextColor="White"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
Background = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 1),
GradientStops =
{
new GradientStop { Color = Color.FromArgb("#6a11cb"), Offset = 0.0f },
new GradientStop { Color = Color.FromArgb("#2575fc"), Offset = 1.0f }
}
},
Content = new Label
{
Text = "Gradient card",
TextColor = Colors.White
}
};Transparent Backgrounds
var card = new SfCardView
{
BackgroundColor = Colors.Transparent,
Content = new Label { Text = "Transparent card" }
};Indicator Customization
Indicators are visual elements (usually a colored line/bar) that can appear on any edge of the card to signify status, category, or importance.
IndicatorColor Property
Sets the color of the indicator.
Type: Color Default: Transparent
XAML:
<cards:SfCardView IndicatorColor="Red" IndicatorThickness="5" IndicatorPosition="Left">
<Label Text="Card with red indicator"/>
</cards:SfCardView>C#:
var card = new SfCardView
{
IndicatorColor = Colors.Red,
IndicatorThickness = 5,
IndicatorPosition = IndicatorPosition.Left,
Content = new Label { Text = "Card with red indicator" }
};IndicatorThickness Property
Sets the thickness of the indicator line.
Type: double Default: 0
Examples:
// Subtle indicator
card.IndicatorThickness = 3;
// Standard indicator
card.IndicatorThickness = 5;
// Prominent indicator
card.IndicatorThickness = 8;
// Bold indicator
card.IndicatorThickness = 12;IndicatorPosition Property
Sets the position of the indicator.
Type: IndicatorPosition (enum) Values: Top, Bottom, Left, Right Default: Left
XAML:
<!-- Top indicator -->
<cards:SfCardView IndicatorColor="Blue" IndicatorThickness="4" IndicatorPosition="Top">
<Label Text="Top indicator"/>
</cards:SfCardView>
<!-- Right indicator -->
<cards:SfCardView IndicatorColor="Green" IndicatorThickness="4" IndicatorPosition="Right">
<Label Text="Right indicator"/>
</cards:SfCardView>
<!-- Bottom indicator -->
<cards:SfCardView IndicatorColor="Orange" IndicatorThickness="4" IndicatorPosition="Bottom">
<Label Text="Bottom indicator"/>
</cards:SfCardView>C#:
// Left indicator (default)
card.IndicatorPosition = IndicatorPosition.Left;
// Top indicator
card.IndicatorPosition = IndicatorPosition.Top;
// Right indicator
card.IndicatorPosition = IndicatorPosition.Right;
// Bottom indicator
card.IndicatorPosition = IndicatorPosition.Bottom;Indicator Use Cases
Status Indication:
// Priority levels
var highPriorityCard = new SfCardView
{
IndicatorColor = Colors.Red,
IndicatorThickness = 5,
IndicatorPosition = IndicatorPosition.Left
};
var mediumPriorityCard = new SfCardView
{
IndicatorColor = Colors.Orange,
IndicatorThickness = 5,
IndicatorPosition = IndicatorPosition.Left
};
var lowPriorityCard = new SfCardView
{
IndicatorColor = Colors.Green,
IndicatorThickness = 5,
IndicatorPosition = IndicatorPosition.Left
};Category Indication:
public SfCardView CreateCategoryCard(string category)
{
var colorMap = new Dictionary<string, Color>
{
{ "Work", Colors.Blue },
{ "Personal", Colors.Green },
{ "Urgent", Colors.Red },
{ "Ideas", Colors.Purple }
};
return new SfCardView
{
IndicatorColor = colorMap[category],
IndicatorThickness = 6,
IndicatorPosition = IndicatorPosition.Left,
Content = new Label { Text = $"{category} Task" }
};
}Advanced Styling Examples
Example 1: Credit Card Design
public SfCardView CreateCreditCard(string bankName, string cardNumber, string holderName)
{
// Note: cardNumber parameter accepts masked numbers like "•••• •••• •••• 4242" or placeholder values like "XXXX XXXX XXXX 0000"
var card = new SfCardView
{
BackgroundColor = Color.FromArgb("#472902"),
CornerRadius = 15,
HeightRequest = 200,
WidthRequest = 350,
Margin = 20,
};
var grid = new Grid
{
Padding = 20,
RowDefinitions =
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = 30 },
new RowDefinition { Height = GridLength.Auto }
}
};
// Bank name
grid.Add(new Label
{
Text = bankName,
TextColor = Colors.White,
FontSize = 20,
FontAttributes = FontAttributes.Bold,
HorizontalOptions = LayoutOptions.Start
}, 0, 0);
// Chip and card type
var chipGrid = new Grid
{
Padding = new Thickness(0, 20, 0, 15),
ColumnDefinitions =
{
new ColumnDefinition { Width = 60 },
new ColumnDefinition { Width = GridLength.Star }
}
};
chipGrid.Add(new Image
{
Source = "cardchip.png",
WidthRequest = 60,
HeightRequest = 30,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
}, 0, 0);
chipGrid.Add(new Label
{
Text = "Business Elite",
FontAttributes = FontAttributes.Bold,
TextColor = Colors.White,
FontSize = 17,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.Center,
Padding = new Thickness(30, 0, 0, 0)
}, 1, 0);
grid.Add(chipGrid, 0, 1);
// Cardholder name
grid.Add(new Label
{
Text = holderName,
FontSize = 17,
FontAttributes = FontAttributes.Bold,
TextColor = Colors.White,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.End
}, 0, 2);
// Card number (always use masked or placeholder values, never actual card numbers)
grid.Add(new Label
{
Text = cardNumber,
TextColor = Colors.White,
FontSize = 16,
HorizontalOptions = LayoutOptions.Start,
VerticalOptions = LayoutOptions.End,
Padding = new Thickness(0, 10, 0, 0),
LetterSpacing = 2
}, 0, 3);
card.Content = grid;
return card;
}
// Usage
var creditCard = CreateCreditCard(
"Wells Fargo",
"•••• •••• •••• 4242",
"John Developer"
);Example 2: Material Design Card
public SfCardView CreateMaterialCard(string title, string subtitle, string body)
{
var card = new SfCardView
{
BackgroundColor = Colors.White,
CornerRadius = 4,
BorderWidth = 0,
Margin = 10,
};
var layout = new VerticalStackLayout
{
Padding = 16,
Spacing = 8
};
layout.Children.Add(new Label
{
Text = title,
FontSize = 20,
FontAttributes = FontAttributes.Bold,
TextColor = Colors.Black
});
layout.Children.Add(new Label
{
Text = subtitle,
FontSize = 14,
TextColor = Colors.Gray
});
layout.Children.Add(new BoxView
{
HeightRequest = 1,
BackgroundColor = Colors.LightGray,
Margin = new Thickness(0, 8)
});
layout.Children.Add(new Label
{
Text = body,
FontSize = 14,
TextColor = Colors.DarkGray
});
card.Content = layout;
return card;
}Example 3: Status Card with Indicator
public SfCardView CreateStatusCard(string status, string message, Color statusColor)
{
var card = new SfCardView
{
BackgroundColor = Colors.White,
CornerRadius = 8,
BorderWidth = 1,
BorderColor = Colors.LightGray,
Margin = 10,
IndicatorColor = statusColor,
IndicatorThickness = 6,
IndicatorPosition = IndicatorPosition.Left
};
var layout = new VerticalStackLayout
{
Padding = 15,
Spacing = 5
};
layout.Children.Add(new Label
{
Text = status.ToUpper(),
FontSize = 12,
FontAttributes = FontAttributes.Bold,
TextColor = statusColor
});
layout.Children.Add(new Label
{
Text = message,
FontSize = 16,
TextColor = Colors.Black
});
card.Content = layout;
return card;
}
// Usage
var successCard = CreateStatusCard("Success", "Operation completed", Colors.Green);
var warningCard = CreateStatusCard("Warning", "Please review", Colors.Orange);
var errorCard = CreateStatusCard("Error", "Something went wrong", Colors.Red);Example 4: Image Card with Gradient Overlay
public SfCardView CreateImageCard(string imageUrl, string title, string subtitle)
{
var card = new SfCardView
{
CornerRadius = 15,
HeightRequest = 300,
WidthRequest = 250,
Margin = 10
};
var grid = new Grid();
// Background image
grid.Children.Add(new Image
{
Source = imageUrl,
Aspect = Aspect.AspectFill
});
// Gradient overlay
var overlayGrid = new Grid
{
VerticalOptions = LayoutOptions.End
};
overlayGrid.Background = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(0, 1),
GradientStops =
{
new GradientStop { Color = Colors.Transparent, Offset = 0.0f },
new GradientStop { Color = Colors.Black.WithAlpha(0.8f), Offset = 1.0f }
}
};
var textLayout = new VerticalStackLayout
{
Padding = 20,
Spacing = 5
};
textLayout.Children.Add(new Label
{
Text = title,
FontSize = 22,
FontAttributes = FontAttributes.Bold,
TextColor = Colors.White
});
textLayout.Children.Add(new Label
{
Text = subtitle,
FontSize = 14,
TextColor = Colors.White
});
overlayGrid.Children.Add(textLayout);
grid.Children.Add(overlayGrid);
card.Content = grid;
return card;
}Best Practices
1. Consistent Corner Radius
Use consistent corner radius across your app:
// Define constants
public static class CardStyles
{
public const double StandardRadius = 12;
public const double SmallRadius = 8;
public const double LargeRadius = 20;
}
// Apply consistently
var card = new SfCardView { CornerRadius = CardStyles.StandardRadius };2. Use Indicators for Status
Leverage indicators for quick visual scanning:
public static Color GetPriorityColor(Priority priority)
{
return priority switch
{
Priority.High => Colors.Red,
Priority.Medium => Colors.Orange,
Priority.Low => Colors.Green,
_ => Colors.Gray
};
}3. Match Your Brand
Create themed card styles:
public static SfCardView CreateBrandedCard()
{
return new SfCardView
{
BackgroundColor = AppColors.Primary,
CornerRadius = AppSizes.CornerRadius,
BorderWidth = 0,
};
}4. Consider Dark Mode
Adjust colors for theme:
var isDarkMode = Application.Current.RequestedTheme == AppTheme.Dark;
var card = new SfCardView
{
BackgroundColor = isDarkMode ? Colors.Dark : Colors.White,
BorderColor = isDarkMode ? Colors.DarkGray : Colors.LightGray
};5. Performance Considerations
- Limit shadow usage on many cards
- Use simple gradients over complex ones
- Avoid unnecessary transparency layers
Data Binding with BindableLayout
Table of Contents
- Overview
- Setting Up ViewModel
- Populating CardLayout with Data
- Defining Card Appearance
- Complete Examples
- Advanced Patterns
- Best Practices
Overview
SfCardLayout supports data binding through .NET MAUI's BindableLayout feature. This allows you to dynamically generate cards from a data collection, making it easy to create data-driven card interfaces without manually creating each card.
Key Benefits:
- Automatic card generation from data sources
- Clean separation of data and UI
- MVVM pattern support
- Observable collection support for dynamic updates
- Simplified code maintenance
Since SfCardLayout is an extended class of Layout<T>, it inherits full BindableLayout capabilities.
Setting Up ViewModel
Step 1: Define Data Model
Create a simple model class that represents the data for each card:
public class CardItem
{
public string Title { get; set; }
public string Description { get; set; }
public Color BackgroundColor { get; set; }
public string ImageUrl { get; set; }
}More Complex Model Example:
public class ProductCard
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ImageUrl { get; set; }
public string Category { get; set; }
public double Rating { get; set; }
public bool InStock { get; set; }
}Step 2: Create ViewModel
Initialize a model collection in your ViewModel:
Simple ViewModel:
public class ViewModel
{
public ObservableCollection<string> Colors { get; set; }
public ViewModel()
{
Colors = new ObservableCollection<string>
{
"Cyan",
"Yellow",
"Orange"
};
}
}MVVM ViewModel with INotifyPropertyChanged:
using System.Collections.ObjectModel;
using System.ComponentModel;
public class CardsViewModel : INotifyPropertyChanged
{
private ObservableCollection<CardItem> _cards;
public ObservableCollection<CardItem> Cards
{
get => _cards;
set
{
_cards = value;
OnPropertyChanged(nameof(Cards));
}
}
public CardsViewModel()
{
LoadCards();
}
private void LoadCards()
{
Cards = new ObservableCollection<CardItem>
{
new CardItem
{
Title = "Morning Routine",
Description = "Start your day right",
BackgroundColor = Colors.Cyan
},
new CardItem
{
Title = "Work Tasks",
Description = "Complete project milestones",
BackgroundColor = Colors.Yellow
},
new CardItem
{
Title = "Evening Plans",
Description = "Relax and unwind",
BackgroundColor = Colors.Orange
}
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}Step 3: Set BindingContext
Set the ViewModel instance as the BindingContext of your page.
XAML:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cards="clr-namespace:Syncfusion.Maui.Toolkit.Cards;assembly=Syncfusion.Maui.Toolkit"
xmlns:local="clr-namespace:YourNamespace"
x:Class="YourNamespace.CardPage">
<ContentPage.BindingContext>
<local:CardsViewModel/>
</ContentPage.BindingContext>
<!-- Your UI here -->
</ContentPage>C#:
public partial class CardPage : ContentPage
{
public CardPage()
{
InitializeComponent();
this.BindingContext = new CardsViewModel();
}
}Populating CardLayout with Data
Use BindableLayout.ItemsSource to bind your data collection to the SfCardLayout.
XAML:
<cards:SfCardLayout BindableLayout.ItemsSource="{Binding Cards}"
HeightRequest="500"
SwipeDirection="Left"
BackgroundColor="#F0F0F0">
<!-- ItemTemplate defined in next section -->
</cards:SfCardLayout>C#:
SfCardLayout cardLayout = new SfCardLayout
{
HeightRequest = 500,
SwipeDirection = CardSwipeDirection.Left,
BackgroundColor = Color.FromArgb("#F0F0F0")
};
var viewModel = new CardsViewModel();
this.BindingContext = viewModel;
BindableLayout.SetItemsSource(cardLayout, viewModel.Cards);Defining Card Appearance
Use BindableLayout.ItemTemplate with a DataTemplate to define how each card should look.
Simple Template
XAML:
<cards:SfCardLayout BindableLayout.ItemsSource="{Binding Colors}"
SwipeDirection="Left"
HeightRequest="300"
WidthRequest="300"
BackgroundColor="#F0F0F0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<cards:SfCardView BackgroundColor="{Binding}" CornerRadius="10">
<Label Text="{Binding}"
HorizontalOptions="Center"
VerticalTextAlignment="Center"/>
</cards:SfCardView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</cards:SfCardLayout>C#:
SfCardLayout cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Left,
BackgroundColor = Color.FromArgb("#F0F0F0"),
HeightRequest = 300,
WidthRequest = 300
};
this.BindingContext = new ViewModel();
DataTemplate dataTemplate = new DataTemplate(() =>
{
SfCardView cardView = new SfCardView { CornerRadius = 10 };
cardView.SetBinding(SfCardView.BackgroundColorProperty, ".");
Label label = new Label
{
HorizontalOptions = LayoutOptions.Center,
VerticalTextAlignment = TextAlignment.Center
};
label.SetBinding(Label.TextProperty, ".");
cardView.Content = label;
return cardView;
});
BindableLayout.SetItemTemplate(cardLayout, dataTemplate);
BindableLayout.SetItemsSource(cardLayout, ((ViewModel)BindingContext).Colors);
this.Content = cardLayout;Complex Template
XAML:
<cards:SfCardLayout BindableLayout.ItemsSource="{Binding Cards}"
SwipeDirection="Left"
HeightRequest="500"
BackgroundColor="#F0F0F0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<cards:SfCardView BackgroundColor="{Binding BackgroundColor}"
CornerRadius="15"
Margin="10">
<Grid Padding="20" RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Text="{Binding Title}"
FontSize="24"
FontAttributes="Bold"
TextColor="White"
Grid.Row="0"/>
<Label Text="{Binding Description}"
FontSize="16"
TextColor="White"
VerticalOptions="Center"
Grid.Row="1"/>
</Grid>
</cards:SfCardView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</cards:SfCardLayout>Complete Examples
Example 1: Task Cards
Model:
public class TaskItem
{
public string Title { get; set; }
public string Description { get; set; }
public DateTime DueDate { get; set; }
public Priority Priority { get; set; }
public bool IsCompleted { get; set; }
}
public enum Priority
{
Low,
Medium,
High
}ViewModel:
public class TaskViewModel : INotifyPropertyChanged
{
public ObservableCollection<TaskItem> Tasks { get; set; }
public TaskViewModel()
{
Tasks = new ObservableCollection<TaskItem>
{
new TaskItem
{
Title = "Complete project proposal",
Description = "Prepare and submit Q1 project proposal",
DueDate = DateTime.Now.AddDays(3),
Priority = Priority.High,
IsCompleted = false
},
new TaskItem
{
Title = "Team meeting",
Description = "Weekly sync with development team",
DueDate = DateTime.Now.AddDays(1),
Priority = Priority.Medium,
IsCompleted = false
},
new TaskItem
{
Title = "Code review",
Description = "Review pull requests from team members",
DueDate = DateTime.Now,
Priority = Priority.High,
IsCompleted = false
}
};
}
public void AddTask(TaskItem task)
{
Tasks.Add(task);
}
public void RemoveTask(TaskItem task)
{
Tasks.Remove(task);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}XAML:
<ContentPage.BindingContext>
<local:TaskViewModel/>
</ContentPage.BindingContext>
<cards:SfCardLayout BindableLayout.ItemsSource="{Binding Tasks}"
SwipeDirection="Left"
ShowSwipedCard="True"
HeightRequest="550"
BackgroundColor="#F5F5F5">
<BindableLayout.ItemTemplate>
<DataTemplate>
<cards:SfCardView BackgroundColor="White"
CornerRadius="12"
BorderWidth="1"
BorderColor="LightGray"
Margin="15">
<!-- Indicator color based on priority -->
<cards:SfCardView.IndicatorColor>
<Binding Path="Priority">
<Binding.Converter>
<local:PriorityToColorConverter/>
</Binding.Converter>
</Binding>
</cards:SfCardView.IndicatorColor>
<cards:SfCardView.IndicatorThickness>
<x:Double>6</x:Double>
</cards:SfCardView.IndicatorThickness>
<cards:SfCardView.IndicatorPosition>
<IndicatorPosition>Left</IndicatorPosition>
</cards:SfCardView.IndicatorPosition>
<Grid Padding="20" RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Text="{Binding Title}"
FontSize="20"
FontAttributes="Bold"
Grid.Row="0"/>
<Label Text="{Binding Description}"
FontSize="14"
TextColor="Gray"
Grid.Row="1"/>
<Label Grid.Row="2">
<Label.FormattedText>
<FormattedString>
<Span Text="Due: " FontAttributes="Bold"/>
<Span Text="{Binding DueDate, StringFormat='{0:MMM dd, yyyy}'}"/>
</FormattedString>
</Label.FormattedText>
</Label>
<Label Text="{Binding Priority, StringFormat='Priority: {0}'}"
FontSize="12"
Grid.Row="3"/>
</Grid>
</cards:SfCardView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</cards:SfCardLayout>Converter:
public class PriorityToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Priority priority)
{
return priority switch
{
Priority.High => Colors.Red,
Priority.Medium => Colors.Orange,
Priority.Low => Colors.Green,
_ => Colors.Gray
};
}
return Colors.Gray;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}Example 2: Product Catalog
Model:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ImageUrl { get; set; }
public double Rating { get; set; }
public bool InStock { get; set; }
}ViewModel:
public class ProductViewModel : INotifyPropertyChanged
{
public ObservableCollection<Product> Products { get; set; }
public ProductViewModel()
{
LoadProducts();
}
private async void LoadProducts()
{
// Simulate API call
Products = new ObservableCollection<Product>
{
new Product
{
Id = 1,
Name = "Wireless Headphones",
Description = "Premium noise-cancelling headphones",
Price = 299.99m,
ImageUrl = "headphones.jpg",
Rating = 4.5,
InStock = true
},
new Product
{
Id = 2,
Name = "Smart Watch",
Description = "Fitness tracking and notifications",
Price = 399.99m,
ImageUrl = "smartwatch.jpg",
Rating = 4.7,
InStock = true
}
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}XAML with Image Cards:
<cards:SfCardLayout BindableLayout.ItemsSource="{Binding Products}"
SwipeDirection="Left"
HeightRequest="600"
WidthRequest="350"
BackgroundColor="#F0F0F0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<cards:SfCardView BackgroundColor="White"
CornerRadius="15"
Margin="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="250"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Product Image -->
<Image Source="{Binding ImageUrl}"
Aspect="AspectFill"
Grid.Row="0"/>
<!-- Product Info -->
<VerticalStackLayout Padding="15" Spacing="8" Grid.Row="1">
<Label Text="{Binding Name}"
FontSize="20"
FontAttributes="Bold"/>
<Label Text="{Binding Description}"
FontSize="14"
TextColor="Gray"
MaxLines="2"/>
<HorizontalStackLayout Spacing="10">
<Label Text="⭐"
FontSize="16"/>
<Label Text="{Binding Rating, StringFormat='{0:F1}'}"
FontSize="16"
VerticalOptions="Center"/>
</HorizontalStackLayout>
<Label Text="{Binding Price, StringFormat='${0:F2}'}"
FontSize="24"
FontAttributes="Bold"
TextColor="Green"/>
<Label Text="In Stock"
FontSize="12"
TextColor="Green"
IsVisible="{Binding InStock}"/>
</VerticalStackLayout>
</Grid>
</cards:SfCardView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</cards:SfCardLayout>Advanced Patterns
Dynamic Updates
ObservableCollection automatically updates the UI when items change:
// Add new card
viewModel.Cards.Add(new CardItem
{
Title = "New Task",
Description = "Just added"
});
// Remove card
viewModel.Cards.RemoveAt(0);
// Clear all
viewModel.Cards.Clear();
// Update existing item
viewModel.Cards[0].Title = "Updated Title";
viewModel.Cards[0].OnPropertyChanged(nameof(CardItem.Title));Best Practices
1. Use ObservableCollection
Always use ObservableCollection<T> for automatic UI updates:
public ObservableCollection<CardItem> Cards { get; set; } // ✓ Good
public List<CardItem> Cards { get; set; } // ✗ Won't update UI automatically2. Implement INotifyPropertyChanged
For item property changes to reflect in UI:
public class CardItem : INotifyPropertyChanged
{
private string _title;
public string Title
{
get => _title;
set
{
_title = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}3. Optimize Performance
- Limit initial card count (lazy loading)
- Use simple DataTemplates
- Avoid heavy computations in templates
- Consider virtualization for large datasets
4. Handle Empty States
<Grid>
<cards:SfCardLayout BindableLayout.ItemsSource="{Binding Cards}"
IsVisible="{Binding HasCards}"/>
<Label Text="No cards available"
IsVisible="{Binding HasNoCards}"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>Events and Interactions
Table of Contents
- Overview
- Tapped Event
- VisibleIndexChanging Event
- VisibleIndexChanged Event
- Dismissing Event
- Dismissed Event
- Event Usage Patterns
- Best Practices
Overview
The .NET MAUI Cards control provides comprehensive event handling for user interactions. Events help you respond to user actions like tapping cards, swiping between cards, and dismissing cards.
Available Events:
SfCardLayout Events:
Tapped- Fires when any card is tappedVisibleIndexChanging- Fires before visible card changes (cancelable)VisibleIndexChanged- Fires after visible card changes
SfCardView Events (standalone only):
Dismissing- Fires before card dismissal (cancelable)Dismissed- Fires after card is dismissed
Important: Dismissing and Dismissed events only work for standalone SfCardView, not when it's a child of SfCardLayout.
Tapped Event
The Tapped event is triggered when any card view in the card layout is tapped.
Event Handler Signature:
void OnCardTapped(object sender, CardTappedEventArgs e)Event Arguments:
CardView- Gets the tappedSfCardViewinstance
Basic Usage
XAML:
<cards:SfCardLayout Tapped="OnCardTapped" HeightRequest="400">
<cards:SfCardView>
<Label Text="Card 1" BackgroundColor="Cyan"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 2" BackgroundColor="Yellow"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 3" BackgroundColor="Orange"/>
</cards:SfCardView>
</cards:SfCardLayout>Code-behind:
private void OnCardTapped(object sender, CardTappedEventArgs e)
{
var tappedCard = e.CardView;
DisplayAlert("Card Tapped", "You tapped a card!", "OK");
}Example: Navigate on Tap
private void OnCardTapped(object sender, CardTappedEventArgs e)
{
var cardView = e.CardView;
// Get card content or data
if (cardView.Content is Label label)
{
string cardText = label.Text;
// Navigate to detail page
Navigation.PushAsync(new CardDetailPage(cardText));
}
}Example: Toggle Selection
private SfCardView selectedCard = null;
private void OnCardTapped(object sender, CardTappedEventArgs e)
{
var tappedCard = e.CardView;
// Deselect previous
if (selectedCard != null)
{
selectedCard.BorderWidth = 0;
}
// Select tapped card
selectedCard = tappedCard;
selectedCard.BorderWidth = 3;
selectedCard.BorderColor = Colors.Blue;
}Example: Expand Card Details
private Dictionary<SfCardView, bool> expandedStates = new();
private void OnCardTapped(object sender, CardTappedEventArgs e)
{
var card = e.CardView;
if (!expandedStates.ContainsKey(card))
expandedStates[card] = false;
// Toggle expanded state
expandedStates[card] = !expandedStates[card];
// Animate height change
if (expandedStates[card])
{
card.HeightRequest = 400; // Expanded
}
else
{
card.HeightRequest = 200; // Collapsed
}
}VisibleIndexChanging Event
The VisibleIndexChanging event fires before the visible card index changes. This event can be canceled to prevent the card change.
Event Handler Signature:
void OnVisibleIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)Event Arguments:
OldIndex- Index of the current cardNewIndex- Index of the card that will become visibleCancel- Set totrueto cancel the index change
Basic Usage
XAML:
<cards:SfCardLayout VisibleIndexChanging="OnVisibleIndexChanging" HeightRequest="400">
<cards:SfCardView>
<Label Text="Card 0" BackgroundColor="Cyan"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 1" BackgroundColor="Yellow"/>
</cards:SfCardView>
<cards:SfCardView>
<Label Text="Card 2" BackgroundColor="Orange"/>
</cards:SfCardView>
</cards:SfCardLayout>Code-behind:
private void OnVisibleIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)
{
Console.WriteLine($"Changing from card {e.OldIndex} to card {e.NewIndex}");
}Example: Prevent Navigation to Specific Card
private void OnVisibleIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)
{
// Prevent navigating to card at index 2
if (e.NewIndex == 2)
{
e.Cancel = true;
DisplayAlert("Restricted", "This card is locked", "OK");
}
}Example: Confirmation Dialog
private async void OnVisibleIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)
{
// Ask for confirmation before moving to next card
bool answer = await DisplayAlert(
"Confirm",
"Are you sure you want to move to the next card?",
"Yes",
"No"
);
if (!answer)
{
e.Cancel = true;
}
}Example: Validate Before Proceeding
private void OnVisibleIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)
{
// Validate current card before allowing navigation
if (!IsCurrentCardValid(e.OldIndex))
{
e.Cancel = true;
DisplayAlert("Validation Error", "Please complete all fields", "OK");
}
}
private bool IsCurrentCardValid(int cardIndex)
{
// Implement validation logic
return true;
}Example: Track Swipe Direction
private void OnVisibleIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)
{
if (e.NewIndex > e.OldIndex)
{
Console.WriteLine("Swiping left (forward)");
}
else
{
Console.WriteLine("Swiping right (backward)");
}
}VisibleIndexChanged Event
The VisibleIndexChanged event fires after the visible card index has changed.
Event Handler Signature:
void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)Event Arguments:
OldIndex- Index of the previous cardNewIndex- Index of the current visible card
Basic Usage
XAML:
<cards:SfCardLayout VisibleIndexChanged="OnVisibleIndexChanged" HeightRequest="400">
<!-- Cards -->
</cards:SfCardLayout>Code-behind:
private void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
Console.WriteLine($"Changed from card {e.OldIndex} to card {e.NewIndex}");
}Example: Update UI Indicators
private Label pageIndicator;
private void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
var cardLayout = sender as SfCardLayout;
int totalCards = cardLayout.Children.Count;
// Update page indicator
pageIndicator.Text = $"{e.NewIndex + 1} / {totalCards}";
}Example: Track Analytics
private void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
// Log card views for analytics
LogCardView(e.NewIndex, DateTime.Now);
// Track user engagement
TrackSwipeDirection(e.OldIndex, e.NewIndex);
}
private void LogCardView(int cardIndex, DateTime timestamp)
{
Console.WriteLine($"Card {cardIndex} viewed at {timestamp}");
// Send to analytics service
}
private void TrackSwipeDirection(int oldIndex, int newIndex)
{
var direction = newIndex > oldIndex ? "forward" : "backward";
Console.WriteLine($"User swiped {direction}");
}Example: Preload Next Card Data
private void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
var cardLayout = sender as SfCardLayout;
int nextIndex = e.NewIndex + 1;
// Preload data for next card
if (nextIndex < cardLayout.Children.Count)
{
PreloadCardData(nextIndex);
}
}
private async void PreloadCardData(int index)
{
// Load images, data, etc. for better performance
Console.WriteLine($"Preloading data for card {index}");
}Example: Dating App Like/Pass
private List<Profile> profiles;
private List<Profile> likedProfiles = new();
private List<Profile> passedProfiles = new();
private void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
// Determine action based on swipe direction
if (e.NewIndex > e.OldIndex)
{
// Swiped left - Pass
passedProfiles.Add(profiles[e.OldIndex]);
Console.WriteLine($"Passed on profile {e.OldIndex}");
}
else
{
// Swiped right - Like
likedProfiles.Add(profiles[e.OldIndex]);
Console.WriteLine($"Liked profile {e.OldIndex}");
}
// Check if all cards viewed
if (e.NewIndex == profiles.Count - 1)
{
DisplayAlert("Complete", $"Liked: {likedProfiles.Count}, Passed: {passedProfiles.Count}", "OK");
}
}Dismissing Event
The Dismissing event fires when a card is about to be dismissed by swiping. This event can be canceled to prevent dismissal.
Event Handler Signature:
void OnCardDismissing(object sender, CardDismissingEventArgs e)Event Arguments:
DismissDirection- Direction of the dismissal (Left or Right)Cancel- Set totrueto prevent dismissal
IMPORTANT: This event only works for standalone SfCardView with SwipeToDismiss="True", NOT when it's a child of SfCardLayout.
Basic Usage
XAML:
<cards:SfCardView Dismissing="OnCardDismissing"
SwipeToDismiss="True"
HeightRequest="200">
<Label Text="Swipe to dismiss"/>
</cards:SfCardView>Code-behind:
private void OnCardDismissing(object sender, CardDismissingEventArgs e)
{
Console.WriteLine($"Card dismissing in direction: {e.DismissDirection}");
}Example: Confirmation Before Dismiss
private async void OnCardDismissing(object sender, CardDismissingEventArgs e)
{
bool answer = await DisplayAlert(
"Confirm",
"Are you sure you want to dismiss this card?",
"Yes",
"No"
);
if (!answer)
{
e.Cancel = true;
}
}Example: Prevent Accidental Dismissal
private void OnCardDismissing(object sender, CardDismissingEventArgs e)
{
// Always cancel and require long press or button
e.Cancel = true;
DisplayAlert("Tip", "Use the delete button to remove this card", "OK");
}Example: Direction-Based Actions
private void OnCardDismissing(object sender, CardDismissingEventArgs e)
{
if (e.DismissDirection == SwipeDirection.Left)
{
// Allow left swipe for delete
Console.WriteLine("Deleting card");
}
else if (e.DismissDirection == SwipeDirection.Right)
{
// Cancel right swipe for archive
e.Cancel = true;
ArchiveCard();
DisplayAlert("Archived", "Card archived instead of deleted", "OK");
}
}Dismissed Event
The Dismissed event fires after a card has been successfully dismissed.
Event Handler Signature:
void OnCardDismissed(object sender, CardDismissedEventArgs e)Event Arguments:
DismissDirection- Direction of the dismissal (Left or Right)
IMPORTANT: This event only works for standalone SfCardView with SwipeToDismiss="True", NOT when it's a child of SfCardLayout.
Basic Usage
XAML:
<cards:SfCardView Dismissed="OnCardDismissed"
SwipeToDismiss="True"
HeightRequest="200">
<Label Text="Swipe to dismiss"/>
</cards:SfCardView>Code-behind:
private void OnCardDismissed(object sender, CardDismissedEventArgs e)
{
Console.WriteLine($"Card dismissed in direction: {e.DismissDirection}");
}Example: Clean Up Resources
private void OnCardDismissed(object sender, CardDismissedEventArgs e)
{
var card = sender as SfCardView;
// Clean up resources
if (card.Content is Image image)
{
image.Source = null;
}
// Remove from parent
if (card.Parent is Layout parent)
{
parent.Children.Remove(card);
}
Console.WriteLine($"Card dismissed and cleaned up");
}Example: Undo Functionality
private Stack<SfCardView> dismissedCards = new();
private void OnCardDismissed(object sender, CardDismissedEventArgs e)
{
var card = sender as SfCardView;
// Store for undo
dismissedCards.Push(card);
// Show undo toast
ShowUndoToast();
}
private async void ShowUndoToast()
{
bool undo = await DisplayAlert("Dismissed", "Card dismissed", "Undo", "OK");
if (undo && dismissedCards.Count > 0)
{
var card = dismissedCards.Pop();
card.IsDismissed = false;
}
}Example: Direction-Based Actions
private void OnCardDismissed(object sender, CardDismissedEventArgs e)
{
if (e.DismissDirection == SwipeDirection.Left)
{
// Left swipe - Delete
DeleteCard(sender as SfCardView);
}
else if (e.DismissDirection == SwipeDirection.Right)
{
// Right swipe - Archive
ArchiveCard(sender as SfCardView);
}
}
private void DeleteCard(SfCardView card)
{
Console.WriteLine("Card deleted permanently");
// Remove from database
}
private void ArchiveCard(SfCardView card)
{
Console.WriteLine("Card archived");
// Move to archive
}Example: Update Counter
private int dismissedCount = 0;
private Label counterLabel;
private void OnCardDismissed(object sender, CardDismissedEventArgs e)
{
dismissedCount++;
counterLabel.Text = $"Dismissed: {dismissedCount}";
}Event Usage Patterns
Pattern 1: Complete Card Lifecycle
public class CardWithLifecycle : SfCardView
{
public CardWithLifecycle()
{
SwipeToDismiss = true;
// Subscribe to events
Dismissing += OnDismissing;
Dismissed += OnDismissed;
}
private void OnDismissing(object sender, CardDismissingEventArgs e)
{
Console.WriteLine($"Dismissing: {e.DismissDirection}");
// Validation
if (!CanDismiss())
{
e.Cancel = true;
}
}
private void OnDismissed(object sender, CardDismissedEventArgs e)
{
Console.WriteLine($"Dismissed: {e.DismissDirection}");
// Cleanup
Cleanup();
}
private bool CanDismiss()
{
// Implement validation
return true;
}
private void Cleanup()
{
// Release resources
Content = null;
}
}Pattern 2: Card Layout with Full Event Handling
public class InteractiveCardLayout : ContentView
{
private SfCardLayout cardLayout;
private Label statusLabel;
public InteractiveCardLayout()
{
cardLayout = new SfCardLayout
{
SwipeDirection = CardSwipeDirection.Left,
HeightRequest = 500
};
// Subscribe to all events
cardLayout.Tapped += OnCardTapped;
cardLayout.VisibleIndexChanging += OnIndexChanging;
cardLayout.VisibleIndexChanged += OnIndexChanged;
statusLabel = new Label { HorizontalOptions = LayoutOptions.Center };
Content = new VerticalStackLayout
{
Children = { cardLayout, statusLabel }
};
}
private void OnCardTapped(object sender, CardTappedEventArgs e)
{
statusLabel.Text = "Card tapped!";
}
private void OnIndexChanging(object sender, CardVisibleIndexChangingEventArgs e)
{
statusLabel.Text = $"Changing: {e.OldIndex} → {e.NewIndex}";
}
private void OnIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
statusLabel.Text = $"Now showing card {e.NewIndex}";
}
}Best Practices
1. Unsubscribe from Events
protected override void OnDisappearing()
{
base.OnDisappearing();
// Unsubscribe to prevent memory leaks
cardLayout.Tapped -= OnCardTapped;
cardLayout.VisibleIndexChanged -= OnVisibleIndexChanged;
}2. Handle Async Operations Safely
private async void OnCardTapped(object sender, CardTappedEventArgs e)
{
try
{
await NavigateToDetailPage();
}
catch (Exception ex)
{
await DisplayAlert("Error", ex.Message, "OK");
}
}3. Use Cancel Wisely
Don't overuse Cancel - it can frustrate users:
// Good: Validate critical operations
if (!IsFormValid())
e.Cancel = true;
// Bad: Cancel too often
if (random.Next(0, 2) == 0) // Don't do this!
e.Cancel = true;4. Provide User Feedback
Always inform users when you cancel their action:
if (!CanProceed())
{
e.Cancel = true;
await DisplayAlert("Cannot Proceed", "Please complete all fields", "OK");
}5. Track for Analytics
private void OnVisibleIndexChanged(object sender, CardVisibleIndexChangedEventArgs e)
{
// Track user behavior
Analytics.TrackEvent("CardSwipe", new Dictionary<string, string>
{
{ "OldIndex", e.OldIndex.ToString() },
{ "NewIndex", e.NewIndex.ToString() },
{ "Direction", e.NewIndex > e.OldIndex ? "forward" : "backward" }
});
}Getting Started with .NET MAUI Cards
This guide covers the installation, and initial setup required to start using Syncfusion .NET MAUI Cards (SfCards) control in your .NET MAUI application.
Step 1: Create a New .NET MAUI Project
Using Visual Studio
1. Go to File > New > Project 2. Choose the .NET MAUI App template 3. Name the project and choose a location 4. Click Next 5. Select the .NET framework version (9.0 or later) 6. Click Create
Using CLI
dotnet new maui -n MyCardApp
cd MyCardAppStep 2: Install Syncfusion.Maui.Toolkit NuGet Package
Using Visual Studio
1. In Solution Explorer, right-click the project 2. Choose Manage NuGet Packages 3. Search for Syncfusion.Maui.Toolkit 4. Install the latest version 5. Ensure all dependencies are installed correctly
Using Package Manager Console
Install-Package Syncfusion.Maui.ToolkitUsing .NET CLI
dotnet add package Syncfusion.Maui.ToolkitStep 3: Register the Syncfusion Handler
Register the Syncfusion Core handler in your MauiProgram.cs file. This is required for all Syncfusion .NET MAUI controls:
File: MauiProgram.cs
using Syncfusion.Maui.Toolkit.Hosting;
namespace MyCardApp
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureSyncfusionToolkit() // Register Syncfusion handler
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
return builder.Build();
}
}
}Important: Place .ConfigureSyncfusionToolkit() immediately after .UseMauiApp<App>() to ensure proper initialization.
Step 4: Add .NET MAUI Cards Control
Import the Namespace
Add the namespace to your XAML or C# file:
XAML:
xmlns:cards="clr-namespace:Syncfusion.Maui.Toolkit.Cards;assembly=Syncfusion.Maui.Toolkit"C#:
using Syncfusion.Maui.Toolkit.Cards;Create Your First Card
XAML Implementation:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cards="clr-namespace:Syncfusion.Maui.Toolkit.Cards;assembly=Syncfusion.Maui.Toolkit"
x:Class="MyCardApp.MainPage">
<cards:SfCardView>
<Label Text="CardView"
Background="PeachPuff"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</cards:SfCardView>
</ContentPage>C# Implementation:
using Syncfusion.Maui.Toolkit.Cards;
namespace MyCardApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
SfCardView cardView = new SfCardView();
cardView.Content = new Label
{
Text = "CardView",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
BackgroundColor = Colors.PeachPuff
};
this.Content = cardView;
}
}
}Basic Card with Swipe-to-Dismiss
Enable swipe-to-dismiss functionality to create a dismissible card:
XAML:
<cards:SfCardView SwipeToDismiss="True">
<Label Text="Swipe me left or right!"
Background="MediumPurple"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"/>
</cards:SfCardView>C#:
SfCardView cardView = new SfCardView
{
SwipeToDismiss = true,
Content = new Label
{
Text = "Swipe me left or right!",
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
BackgroundColor = Colors.MediumPurple
}
};Note: SwipeToDismiss only works for standalone SfCardView, not when it's a child of SfCardLayout.
Creating a Simple Card Layout (Stack)
Create multiple stacked cards with swipe navigation:
XAML:
<cards:SfCardLayout HeightRequest="500" BackgroundColor="#F0F0F0">
<cards:SfCardView CornerRadius="10">
<Label Text="Peach"
BackgroundColor="PeachPuff"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"/>
</cards:SfCardView>
<cards:SfCardView CornerRadius="10">
<Label Text="MediumPurple"
BackgroundColor="MediumPurple"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"/>
</cards:SfCardView>
<cards:SfCardView CornerRadius="10">
<Label Text="LightPink"
BackgroundColor="LightPink"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"/>
</cards:SfCardView>
</cards:SfCardLayout>C#:
SfCardLayout cardLayout = new SfCardLayout
{
HeightRequest = 500,
BackgroundColor = Color.FromArgb("#F0F0F0")
};
// Add children cards
cardLayout.Children.Add(new SfCardView
{
Content = new Label
{
Text = "Peach",
BackgroundColor = Colors.PeachPuff,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center
},
CornerRadius = 10
});
cardLayout.Children.Add(new SfCardView
{
Content = new Label
{
Text = "MediumPurple",
BackgroundColor = Colors.MediumPurple,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center
},
CornerRadius = 10
});
cardLayout.Children.Add(new SfCardView
{
Content = new Label
{
Text = "LightPink",
BackgroundColor = Colors.LightPink,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center
},
CornerRadius = 10
});
this.Content = cardLayout;Quick Verification
Run your application and verify:
1. Card appears - You should see the card with your content 2. Swipe works (if enabled) - Swipe left or right to dismiss 3. Stack navigation (for CardLayout) - Swipe to reveal next card
Troubleshooting Common Issues
Issue: Cards not appearing
Solution: Ensure you called ConfigureSyncfusionToolkit() in MauiProgram.cs
Issue: NuGet package not found
Solution: Check your NuGet package source includes nuget.org
Issue: SwipeToDismiss not working in CardLayout
Explanation: This is by design. SwipeToDismiss only works for standalone SfCardView, not when it's a child of SfCardLayout. In CardLayout, use SwipeDirection for navigation.
Issue: Namespace not found
Solution: Ensure Syncfusion.Maui.Toolkit NuGet package is installed and project is restored.
Next Steps
Now that you have cards working:
- Explore card-views.md for single card features
- Explore card-layouts.md for card stack features
- See customization.md for styling options
- Check events.md for interaction handling
- Review data-binding.md for dynamic cards