6

Multi-Selection per row with Dynamic Data in Xamarin Forms (Part 4)

 3 years ago
source link: https://www.xamboy.com/2021/04/28/multi-selection-per-row-with-dynamic-data-in-xamarin-forms-part-4/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Multi-Selection per row with Dynamic Data in Xamarin Forms (Part 4)

Screen-Shot-2021-01-20-at-5.00.17-PM.png?fit=870%2C982&ssl=1

In the third part of the series about Dynamic Data, we covered how to group items. In this part, we will explora how to do multi-selection per row, reusing the concepts of grouping that we learned in the previous article.

Multi-Selection per row

As an example, we are going to create the following notifications settings page:

It has two groups Development and Administration. Inside each group, we will have these channels: Sms, Email, Push, Phone.

Let’s start!

1.Create your Model

using ReactiveUI;

namespace DynamicDataGroupingSample { public class NotificationConfiguration : ReactiveObjectEx { public NotificationConfiguration(string name, int order, string groupName, int groupOrder,bool smsChannel, bool emailChannel, bool pushNotificationChannel, bool phoneChannel) { Name = name; Order = order; GroupName = groupName; GroupOrder = groupOrder; SmsChannel = smsChannel; EmailChannel = emailChannel; PushNotificationChannel = pushNotificationChannel; PhoneChannel = phoneChannel; }

public string Name { get;} public int Order { get; }

//Group public string GroupName { get; } public int GroupOrder { get; } public string GroupCssIcon { get; } public string GroupFontIcon { get; }

//Channels public bool SmsChannel { get => _smsChannel; set => this.RaiseAndSetIfChanged(ref _smsChannel, value); }

public bool EmailChannel { get => _emailChannel; set => this.RaiseAndSetIfChanged(ref _emailChannel, value); }

public bool PushNotificationChannel { get => _pushNotificationChannel; set => this.RaiseAndSetIfChanged(ref _pushNotificationChannel, value); }

public bool PhoneChannel { get => _phoneChannel; set => this.RaiseAndSetIfChanged(ref _phoneChannel, value); }

private bool _smsChannel; private bool _emailChannel; private bool _pushNotificationChannel; private bool _phoneChannel; } }

Make sure to implement PropertyChanged in the selectable properties: SmsChannel, PhoneChannel, EmailChannel and PushNotificationChannel. Since we want to detect when the checkbox has changed its state in any of them.

Note: Copy the ReactiveObjExt class here.

2.Create the Grouping List

In the ViewModel, let’s create a SourceCache and add a few items.

namespace DynamicDataGroupingSample { public class NotificationConfigurationViewModel : ReactiveObjectEx { public NotificationConfigurationViewModel() { _notificationConfigurationsSourceCache.AddOrUpdate(new List<NotificationConfiguration>() { new NotificationConfiguration("Information", 0,"Development", 0,false, false, true, false), new NotificationConfiguration("Status Changed", 1,"Administration", 1, false, true, false, false), new NotificationConfiguration("Error", 3,"Development", 0, false, true, false, false), new NotificationConfiguration("New Report", 4,"Administration", 1, false, false, false, false), new NotificationConfiguration("Warning", 1,"Development", 0, false, true, false, false), new NotificationConfiguration("Security Update", 2, "Administration", 1, false, false, true, true), new NotificationConfiguration("Verbose", 2, "Development", 0, false, false, false, false), new NotificationConfiguration("Policy Update", 3, "Administration", 1, false, false, false, false) }); var notificationConfigurationItemChanges = _notificationConfigurationsSourceCache.Connect() .RefCount(); notificationConfigurationItemChanges .Sort(SortExpressionComparer<NotificationConfiguration>.Ascending(a => a.GroupOrder)) .Group(x => x.GroupName) .Transform(g => new ObservableGroupedCollection<string, NotificationConfiguration, string>(g, null, Observable.Return<IComparer<NotificationConfiguration>>(SortExpressionComparer<NotificationConfiguration>.Ascending(a => a.Order)))) .Bind(out _groups) .DisposeMany() .Subscribe() .DisposeWith(Subscriptions); }

public ReadOnlyObservableCollection<ObservableGroupedCollection<string, NotificationConfiguration, string>> NotificationGroups => _groups;

private readonly ReadOnlyObservableCollection<ObservableGroupedCollection<string, NotificationConfiguration, string>> _groups;

private SourceCache<NotificationConfiguration, string> _notificationConfigurationsSourceCache = new SourceCache<NotificationConfiguration, string>(x => x.Name); } }

Note: Copy here ObservableGroupedCollection class, here.

3.Observe channel state changes

To observe when a channel has changed its state, we are going to create a reactive pipeline for each channel using WhenPropertyChanged, also using Throttle we will limit notifications emissions when selecting. Finally, will use InvokeCommand to subscribe and invoke a command when the state changes.

namespace DynamicDataGroupingSample { public class NotificationConfigurationViewModel : ReactiveObjectEx { public NotificationConfigurationViewModel() { ... var smsChannelChangedCommand = ReactiveCommand.CreateFromTask<NotificationConfiguration>(OnSmsChannelChanged); var emailChannelChangedCommand = ReactiveCommand.CreateFromTask<NotificationConfiguration>(OnEmailChannelChanged); var pushNotificationChannelChangedCommand = ReactiveCommand.CreateFromTask<NotificationConfiguration>(OnPushNotificationChannelChanged); var phoneChannelChangedCommand = ReactiveCommand.CreateFromTask<NotificationConfiguration>(OnPhoneChannelChanged);

notificationConfigurationItemChanges .WhenPropertyChanged(x => x.SmsChannel , notifyOnInitialValue: false) .Throttle(TimeSpan.FromMilliseconds(SelectionDueMilliseconds), RxApp.TaskpoolScheduler) .Select(x => x.Sender) .InvokeCommand(smsChannelChangedCommand) .DisposeWith(Subscriptions);

notificationConfigurationItemChanges .WhenPropertyChanged(x => x.EmailChannel, notifyOnInitialValue: false) .Throttle(TimeSpan.FromMilliseconds(SelectionDueMilliseconds), RxApp.TaskpoolScheduler) .Select(x => x.Sender) .InvokeCommand(emailChannelChangedCommand) .DisposeWith(Subscriptions);

notificationConfigurationItemChanges .WhenPropertyChanged(x => x.PushNotificationChannel, notifyOnInitialValue: false) .Throttle(TimeSpan.FromMilliseconds(SelectionDueMilliseconds), RxApp.TaskpoolScheduler) .Select(x => x.Sender) .InvokeCommand(pushNotificationChannelChangedCommand) .DisposeWith(Subscriptions);

notificationConfigurationItemChanges .WhenPropertyChanged(x => x.PhoneChannel, notifyOnInitialValue: false) .Throttle(TimeSpan.FromMilliseconds(SelectionDueMilliseconds), RxApp.TaskpoolScheduler) .Select(x => x.Sender) .InvokeCommand(phoneChannelChangedCommand) .DisposeWith(Subscriptions); }

private Task OnPhoneChannelChanged(NotificationConfiguration notificationConfiguration) { System.Diagnostics.Debug.WriteLine($"Phone Channel - Changed - {notificationConfiguration.GroupName}.{notificationConfiguration.Name} - {notificationConfiguration.PhoneChannel}");

return Task.CompletedTask; }

private Task OnPushNotificationChannelChanged(NotificationConfiguration notificationConfiguration) { System.Diagnostics.Debug.WriteLine($"Push Notification Channel - Changed - {notificationConfiguration.GroupName}.{notificationConfiguration.Name} - {notificationConfiguration.PushNotificationChannel}");

return Task.CompletedTask; }

private Task OnEmailChannelChanged(NotificationConfiguration notificationConfiguration) { System.Diagnostics.Debug.WriteLine($"Email Notification Channel - Changed - {notificationConfiguration.GroupName}.{notificationConfiguration.Name} - {notificationConfiguration.EmailChannel}");

return Task.CompletedTask; }

private Task OnSmsChannelChanged(NotificationConfiguration notificationConfiguration) { System.Diagnostics.Debug.WriteLine($"SMS Notification Channel - Changed - {notificationConfiguration.GroupName}.{notificationConfiguration.Name} - {notificationConfiguration.SmsChannel}");

return Task.CompletedTask; } private const int SelectionDueMilliseconds = 250; } }

4.Create the UI

<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="DynamicDataGroupingSample.NotificationConfigurationsPage" Title="Notification Settings"> <CollectionView ItemsSource="{Binding NotificationGroups}" IsGrouped="True"> <CollectionView.GroupHeaderTemplate> <DataTemplate> <Label Padding="10" Text="{Binding Key}" BackgroundColor="CornflowerBlue" FontSize="Large" /> </DataTemplate> </CollectionView.GroupHeaderTemplate> <CollectionView.ItemTemplate> <DataTemplate> <StackLayout> <Label Text="{Binding Name}" FontSize="Large" TextDecorations="Underline" /> <Grid RowDefinitions="Auto, Auto" ColumnDefinitions="*, *, *, *"> <Label Grid.Column="0" Grid.Row="0" Text="Sms" /> <CheckBox Grid.Column="0" Grid.Row="1" IsChecked="{Binding SmsChannel}"/> <Label Grid.Column="1" Grid.Row="0" Text="Email" /> <CheckBox Grid.Column="1" Grid.Row="1" IsChecked="{Binding EmailChannel}"/> <Label Grid.Column="2" Grid.Row="0" Text="Push" /> <CheckBox Grid.Column="2" Grid.Row="1" IsChecked="{Binding PushNotificationChannel}"/> <Label Grid.Column="3" Grid.Row="0" Text="Phone" /> <CheckBox Grid.Column="3" Grid.Row="1" IsChecked="{Binding PhoneChannel}"/> </Grid> </StackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </ContentPage>

If you haven’t fallen in love with Dynamic Data yet, stay tuned for the next part of this series with some more Dynamic Data magic tricks.

Check the full source code here.

Happy Dynamic Data!

Be First to Comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Comment

Name*

Email*

Website

Notify me of follow-up comments by email.

Notify me of new posts by email.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK