How to customize the expander view when loading on demand in Xamarin.Forms TreeView (SfTreeView)
You can customize the load indicator by using the custom expander icon and SfBusyIndicator in Xamarin.Forms SfTreeView. Also, you can customize the load indicator based on level.
You can refer to the following document regarding custom expander icon,
XAML: Expander View – BusyIndicator as load indicator and Image as expander icon
Load custom expander icon and BusyIndicator in the same column and change the visibility based on the TreeViewNode properties using Converters.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TreeViewXamarin"
xmlns:treeview="clr-namespace:Syncfusion.XForms.TreeView;assembly=Syncfusion.SfTreeView.XForms"
xmlns:sfbusyindicator="clr-namespace:Syncfusion.SfBusyIndicator.XForms;assembly=Syncfusion.SfBusyIndicator.XForms"
x:Class="TreeViewXamarin.MainPage" Padding="0,20,0,0">
<ContentPage.BindingContext>
<local:MusicInfoRepository x:Name="viewModel"/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<local:ExpanderIconVisibilityConverter x:Key="ExpanderIconVisibilityConverter"/>
<local:ExpanderIconConverter x:Key="ExpanderIconConverter" />
<local:IndicatorColorConverter x:Key="IndicatorColorConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Behaviors>
<local:Behavior/>
</ContentPage.Behaviors>
<ContentPage.Content>
<treeview:SfTreeView x:Name="treeView" ExpanderWidth="0" ItemTemplateContextType="Node" LoadOnDemandCommand="{Binding TreeViewOnDemandCommand}" ItemsSource="{Binding Menu}">
<treeview:SfTreeView.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid" Padding="5,5,5,5" BackgroundColor="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" Padding="1,0,0,0" VerticalOptions="Center">
<Label LineBreakMode="NoWrap" TextColor="Black" Text="{Binding Content.ItemName}" FontSize="20" VerticalTextAlignment="Center"/>
</Grid>
<Grid >
<Image Source="{Binding IsExpanded, Converter={StaticResource ExpanderIconConverter}}"
IsVisible="{Binding HasChildNodes, Converter={StaticResource ExpanderIconVisibilityConverter}}"
VerticalOptions="Center" HorizontalOptions="Center" HeightRequest="35" WidthRequest="35">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
</Image.GestureRecognizers>
</Image>
<Grid IsVisible="{Binding Content.IsInAnimation, Mode=TwoWay}">
<sfbusyindicator:SfBusyIndicator x:Name="grid1" TextColor="{Binding Level, Converter={StaticResource IndicatorColorConverter}}"
IsBusy="True" Margin="2" BackgroundColor="White" ViewBoxHeight="25" ViewBoxWidth="25" HeightRequest="32" AnimationType="SingleCircle"/>
</Grid>
</Grid>
</Grid>
</DataTemplate>
</treeview:SfTreeView.ItemTemplate>
</treeview:SfTreeView>
</ContentPage.Content>
</ContentPage>
C#: Handled the BusyIndicator visibility based on the IsInAnimation model property
Update the IsInAnimation property in the LoadOnDemandCommand execution method.
namespace TreeViewXamarin
{
public class MusicInfoRepository
{
public ICommand TreeViewOnDemandCommand{ get; set; }
public MusicInfoRepository()
{
TreeViewOnDemandCommand = new Command(ExecuteOnDemandLoading, CanExecuteOnDemandLoading);
}
private bool CanExecuteOnDemandLoading(object sender)
{
var hasChildNodes = ((sender as TreeViewNode).Content as MusicInfo).HasChildNodes;
if (hasChildNodes)
return true;
else
return false;
}
private void ExecuteOnDemandLoading(object obj)
{
var node = obj as TreeViewNode;
// Skip the repeated population of child items when every time the node expands.
if (node.ChildNodes.Count > 0)
{
node.IsExpanded = true;
return;
}
MusicInfo musicInfo = node.Content as MusicInfo;
musicInfo.IsInAnimation = true;
Device.BeginInvokeOnMainThread(async () =>
{
await Task.Delay(500);
var items = GetSubMenu(musicInfo.ID);
// Populating child items for the node in on-demand
node.PopulateChildNodes(items);
if (items.Count() > 0)
node.IsExpanded = true;
musicInfo.IsInAnimation = false;
});
}
}
}
C#
The expander icon visibility is handled based on the HasChildNodes.
namespace TreeViewXamarin
{
public class ExpanderIconVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (!(bool)value) ? false : true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
}
C#: Load indicator color customization
Converter to customize the load indicator color based on the TreeViewNode.Level property.
namespace TreeViewXamarin
{
public class IndicatorColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value == 0 ? Color.Red : Color.Green;
}
}
}
Output