I use a specific Border control multiple times throughout my app. This Border control is displayed as part of a CollectionView. I used VisualStateManager to control the Border color when the Border and it's contained item was selected within the CollectionView. Here is where the Border control was defined:
<CollectionView Margin="0,10,0,0" ItemsLayout="HorizontalList" HorizontalOptions="Center"
ItemsSource="{Binding Source={x:Static vm:WaxItVM.SnowSourceButtons}}"
SelectionMode="Single" SelectedItem="{Binding SelectedSnowSourceButton}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Border StrokeShape="RoundRectangle 10" StrokeThickness="2" Margin="4,0,4,0">
<Image Source="{Binding IconFileName}" Margin="6,6,6,6" WidthRequest="35" HeightRequest="35" VerticalOptions="Center" HorizontalOptions="Center">
<Image.Behaviors>
<mct:IconTintColorBehavior TintColor="{AppThemeBinding Light={StaticResource Black},Dark={StaticResource White}}"/>
</Image.Behaviors>
</Image>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Here is how I used VisualStateManager in the same ContentPage file:
<ContentPage.Resources>
<Style TargetType="Border">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="Stroke" Value="{StaticResource Primary}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White},Dark={StaticResource Black}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
That all worked beautifully. I then decided to extract the Border control into a separate Xaml file named SnowConditionInputButton.xaml containing a ContentView. Here is what that looked like...
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mct="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="FasterWaxer.CustomComponents.SnowConditionInputButton">
<Border StrokeShape="RoundRectangle 10" StrokeThickness="2" Margin="4,0,4,0">
<Image Source="{Binding IconFileName}" Margin="6,6,6,6" WidthRequest="35" HeightRequest="35" VerticalOptions="Center" HorizontalOptions="Center">
<Image.Behaviors>
<mct:IconTintColorBehavior TintColor="{AppThemeBinding Light={StaticResource Black},Dark={StaticResource White}}"/>
</Image.Behaviors>
</Image>
</Border>
</ContentView>
I then changed my ContentPage to:
<CollectionView Margin="0,10,0,0" ItemsLayout="HorizontalList" HorizontalOptions="Center"
ItemsSource="{Binding Source={x:Static vm:WaxItVM.SnowSourceButtons}}"
SelectionMode="Single" SelectedItem="{Binding SelectedSnowSourceButton}">
<CollectionView.ItemTemplate>
<DataTemplate>
<custom_components:SnowConditionInputButton/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When I did that, the each CollectionView item was displayed correctly but the Border color no longer changed when I selected a CollectionView item. It seems that the ContentPage.Resources no longer applied to the Border control when I moved it to the separate ContentView. So, I tried to move VisualStateManager to the ContentView to explicitly control the Border color. When doing so, the Border still doesn't respond to being selected within the CollectionView:
<Border StrokeShape="RoundRectangle 10" StrokeThickness="2" Margin="4,0,4,0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="Stroke" Value="{StaticResource Primary}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White},Dark={StaticResource Black}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
<Image Source="{Binding IconFileName}" Margin="6,6,6,6" WidthRequest="35" HeightRequest="35" VerticalOptions="Center" HorizontalOptions="Center">
<Image.Behaviors>
<mct:IconTintColorBehavior TintColor="{AppThemeBinding Light={StaticResource Black},Dark={StaticResource White}}"/>
</Image.Behaviors>
</Image>
</Border>
How can I extract that Border control and the related VisualStateManager into a separate Xaml file for reuse? As a side note, I don't want that Border configuration to apply to all Borders throughout the app so I don't want to define it as a global Border Style that applies to all Borders. I want to selectively apply it to specific Borders or to all Borders on a page.
Thanks for your help.
You could make some changes to your code:
First, in the ContentView, give a Name to the Border. Let's call it myBorder which will be referenced in our VisualStateManger.
In ContentPage, make some changes to our VisualStateManager. As the VisualStateGroups is attached to Custom Control SnowConditionInputButtonm, we should set the TargetName and Property to Border like the following:
Then easily consume Custom Control in CollectionView:
If you don't want to use Style like the above code, you could easily define VisualStateManager in SnowConditionInputButton. It also works fine.
Hope it works for you.