Advanced Features
Drag & Sort
Section titled “Drag & Sort”Enable reorder controls on a section by setting UseDragSort="True". Each cell gets up/down arrow buttons to move it within the section.
<tv:TableView ItemDroppedCommand="{Binding ItemDroppedCommand}"> <tv:TableRoot> <tv:TableSection Title="Drag to Reorder" UseDragSort="True"> <tv:LabelCell Title="First" ValueText="1" /> <tv:LabelCell Title="Second" ValueText="2" /> <tv:LabelCell Title="Third" ValueText="3" /> </tv:TableSection> </tv:TableRoot></tv:TableView>ItemDroppedCommand
Section titled “ItemDroppedCommand”The ItemDroppedCommand receives an ItemDroppedEventArgs with:
| Property | Type | Description |
|---|---|---|
Section | TvTableSection | The section containing the cell |
Cell | CellBase | The cell that was moved |
FromIndex | int | Original position |
ToIndex | int | New position |
ItemDropped Event
Section titled “ItemDropped Event”You can also use the event-based approach:
tableView.ItemDropped += (sender, args) =>{ Console.WriteLine($"Moved from {args.FromIndex} to {args.ToIndex}");};Scroll Control
Section titled “Scroll Control”From XAML Bindings
Section titled “From XAML Bindings”Trigger scrolling from your view model using bindable properties:
<tv:TableView ScrollToTop="{Binding ShouldScrollTop}" ScrollToBottom="{Binding ShouldScrollBottom}" />Set the bound property to true to trigger the scroll. The control resets it to false after scrolling.
From Code
Section titled “From Code”Use the async methods for programmatic scroll control:
// Scroll to top with animationawait tableView.ScrollToTopAsync(animated: true);
// Scroll to bottom with animationawait tableView.ScrollToBottomAsync(animated: true);Events
Section titled “Events”ModelChanged
Section titled “ModelChanged”Fires when the structure of the TableView changes (sections added/removed, cells added/removed):
tableView.ModelChanged += (sender, args) =>{ Console.WriteLine("TableView structure changed");};CellPropertyChanged
Section titled “CellPropertyChanged”Fires when a property changes on any cell within the TableView:
tableView.CellPropertyChanged += (sender, args) =>{ Console.WriteLine($"Cell property changed: {args.PropertyName}");};Complete Settings Page Example
Section titled “Complete Settings Page Example”Here is a comprehensive example showing multiple cell types, sections, styling, and MVVM bindings:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:tv="http://shiny.net/maui/tableview" x:Class="MyApp.SettingsPage" Title="Settings">
<tv:TableView CellTitleFontSize="16" CellValueTextColor="#007AFF" CellSelectedColor="#E8E8ED" CellAccentColor="#34C759" HeaderFontSize="13" HeaderTextColor="#6D6D72" FooterTextColor="#8E8E93"> <tv:TableRoot>
<!-- Account Section --> <tv:TableSection Title="ACCOUNT"> <tv:LabelCell Title="Name" ValueText="{Binding UserName}" IconSource="person.png" /> <tv:LabelCell Title="Email" ValueText="{Binding UserEmail}" IconSource="email.png" /> <tv:CommandCell Title="Edit Profile" Command="{Binding EditProfileCommand}" ShowArrow="True" IconSource="edit.png" /> </tv:TableSection>
<!-- Preferences Section --> <tv:TableSection Title="PREFERENCES" FooterText="Notifications may use cellular data"> <tv:SwitchCell Title="Push Notifications" On="{Binding PushEnabled, Mode=TwoWay}" IconSource="bell.png" /> <tv:SwitchCell Title="Email Alerts" On="{Binding EmailAlerts, Mode=TwoWay}" IconSource="mail.png" /> <tv:TextPickerCell Title="Language" ItemsSource="{Binding Languages}" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}" IconSource="globe.png" /> </tv:TableSection>
<!-- Appearance Section --> <tv:TableSection Title="APPEARANCE" tv:RadioCell.SelectedValue="{Binding Theme, Mode=TwoWay}"> <tv:RadioCell Title="Light" Value="Light" /> <tv:RadioCell Title="Dark" Value="Dark" /> <tv:RadioCell Title="System" Value="System" /> </tv:TableSection>
<!-- About Section --> <tv:TableSection Title="ABOUT"> <tv:LabelCell Title="Version" ValueText="1.0.0" /> <tv:CommandCell Title="Privacy Policy" Command="{Binding PrivacyCommand}" ShowArrow="True" /> <tv:CommandCell Title="Terms of Service" Command="{Binding TermsCommand}" ShowArrow="True" /> </tv:TableSection>
<!-- Actions --> <tv:TableSection> <tv:ButtonCell Title="Sign Out" Command="{Binding SignOutCommand}" ButtonTextColor="Red" /> </tv:TableSection>
</tv:TableRoot> </tv:TableView></ContentPage>ViewModel
Section titled “ViewModel”public class SettingsViewModel : INotifyPropertyChanged{ private bool _pushEnabled = true; private bool _emailAlerts; private string _theme = "System"; private object? _selectedLanguage;
public string UserName => "Jane Doe"; public string UserEmail => "jane@example.com";
public bool PushEnabled { get => _pushEnabled; set => SetProperty(ref _pushEnabled, value); }
public bool EmailAlerts { get => _emailAlerts; set => SetProperty(ref _emailAlerts, value); }
public string Theme { get => _theme; set => SetProperty(ref _theme, value); }
public List<string> Languages { get; } = ["English", "Spanish", "French", "German"];
public object? SelectedLanguage { get => _selectedLanguage; set => SetProperty(ref _selectedLanguage, value); }
public ICommand EditProfileCommand { get; } public ICommand PrivacyCommand { get; } public ICommand TermsCommand { get; } public ICommand SignOutCommand { get; }
public SettingsViewModel() { EditProfileCommand = new Command(async () => await Shell.Current.GoToAsync("editprofile")); PrivacyCommand = new Command(async () => await Launcher.OpenAsync("https://example.com/privacy")); TermsCommand = new Command(async () => await Launcher.OpenAsync("https://example.com/terms")); SignOutCommand = new Command(async () => { bool confirm = await Application.Current!.Windows[0].Page! .DisplayAlert("Sign Out", "Are you sure?", "Sign Out", "Cancel"); if (confirm) { /* sign out logic */ } }); }
public event PropertyChangedEventHandler? PropertyChanged;
private bool SetProperty<T>(ref T field, T value, [System.Runtime.CompilerServices.CallerMemberName] string? name = null) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); return true; }}