Right Align all items in CollectionView in Xamarin Forms - xamarin

I have been trying to right align all items in Xamarin forms CollectionView, unfortunately the code doesn't work for IOS while it works well in Android. It seems strange. When I load 100 items, only the 1st ten items which appears on the screen are right aligned, but then the rest is not aligned. Additionally, when I clear the collectionview and load next 100 items (this is part of the requirement), then the whole items are not aligned.
<CollectionView ItemsSource="{Binding ArabicListText}" SelectedItem="{Binding SelectedAya}"
SelectionMode="Single" ItemTemplate="{StaticResource ChapterItemTemplate}"
FlowDirection="RightToLeft" x:Name="itemView">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="1"/>
</CollectionView.ItemsLayout>
</CollectionView>
Datatemplate from resources
<DataTemplate x:Key="ChapterItemTemplate">
<SwipeView HorizontalOptions="StartAndExpand">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource LightPageBackgroundPrimaryColor},
Dark={StaticResource DarkPageBackgroundPrimaryColor}}" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource LightPageBackgroundSecondaryColor},
Dark={StaticResource DarkPageBackgroundSecondaryColor}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout Padding="10,0,5,0" HorizontalOptions="StartAndExpand">
<Label LineBreakMode="WordWrap" HorizontalTextAlignment="Start" HorizontalOptions="StartAndExpand" IsVisible="{Binding BindingContext.ShowEnglishVerseNumber,
Source={x:Reference MyPage}, Converter={StaticResource InverterBooleanConverter}}">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding ArabicText.Aya}"
FontSize="{Binding BindingContext.ActiveArabicFont.FontSize, Source={x:Reference MyPage}}"
FontFamily="{Binding BindingContext.ActiveArabicFont.FontPath, Source={x:Reference MyPage}}"/>
<Span
Text="{Binding ArabicText.ArabicAyaNumber, StringFormat='﴿{0}﴾'}"
FontSize="35" FontFamily="Sherzad"></Span>
</FormattedString>
</Label.FormattedText>
</Label>
<BoxView Style="{StaticResource HorizentalLine}" IsVisible="{Binding BindingContext.ShowHorizentalLine, Source={x:Reference MyPage}}"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="2" Command="{Binding BindingContext.ShareAyaCommand,
Source={x:Reference itemView}}"
CommandParameter="{Binding .}"/>
<SwipeGestureRecognizer Direction="Right" Command="{Binding BindingContext.NextChapterCommand,
Source={x:Reference MyPage}}"/>
<SwipeGestureRecognizer Direction="Left" Command="{Binding BindingContext.PreviousChapterCommand,
Source={x:Reference MyPage}}"/>
</StackLayout.GestureRecognizers>
</StackLayout>
</SwipeView>
</DataTemplate>
When I have fewer items says 10, all the items are aligned accordingly. However, when the number of items grow to 100, then strangly, the only few top items are well aligned and the rest are not aligned. When I scroll back to the top, then all the items are aligned incorrectly.
Update 2
If I remove Span and change them to labels then all the labels are aligned accordingly, but having the span creates the problem.

The only temp solution I found is to change Spans to Labels, but it doesn't display text as the Span after one another horizentally. Because using Span I want to show two diff texts after one finishes which I can't acheive similiar result using two Labels.

Related

Collection View outline shows under and over my horizontal collection

I have problem with CollectionView outline. I create simple horizontal colletionView, and it is working, but on top and bottom I have gray outline.
XAML
<CollectionView BackgroundColor="White"
Margin="0,15,0,0"
x:Name="NewSubMenu"
ItemsLayout="HorizontalList"
SelectionMode="Single"
HeightRequest="35"
SelectionChanged="OnCollectionViewSelectionChanged"
ItemsSource="{Binding MyListSource}"
HorizontalOptions="FillAndExpand">
<CollectionView.ItemTemplate >
<DataTemplate>
<Grid BackgroundColor="White" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal" />
<VisualState Name="Selected" >
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
<Setter TargetName="_label" Property="Label.TextColor" Value="Black" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="{Binding Name}"
x:Name="_label" ClassId="{Binding Id}"
TextColor="{StaticResource TamnoBraon}"
TextTransform="Uppercase" Padding="5,1,10,1" FontSize="Large"></Label>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Does anyone have same problem?

Xamarin.Forms - CollectionView SelectedItem doesn't respect VisualStateManager on iOS on load

So,
I have a CollectionView that loads a SelectedItem when the page loads.
I use VisualStateManager to manage the properties of selected and non-selected items, and also to manage the background color of the cell itself.
My problem is that sometimes (randomly) on page load VisualStateManager doesn't set any of the properties correctly on the SelectedItem. This only happens on iOS, it works fine on Android.
My CollectionView code:
<CollectionView
x:Name="DaysList"
ItemsLayout="HorizontalList"
SelectionMode="Single"
VerticalOptions="Start"
HorizontalScrollBarVisibility="Never"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding DaysList}"
SelectedItem="{Binding DaysListSelectedItem, Mode=TwoWay}">
<CollectionView.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="-3,0,-3,40"/>
<On Platform="Android" Value="-3,-40,-3,0"/>
</OnPlatform>
</CollectionView.Margin>
<CollectionView.HeightRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="iOS" Value="74"/>
<On Platform="Android" Value="150"/>
</OnPlatform>
</CollectionView.HeightRequest>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid
Padding="3,0,3,0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal"/>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="Background" Value="#2F2F2F"/>
<Setter TargetName="SelectedFrame" Property="Frame.BackgroundColor" Value="#F0CF4E"/>
<Setter TargetName="SelectedFrame" Property="Frame.WidthRequest" Value="104"/>
<Setter TargetName="SelectedFrame" Property="Frame.HeightRequest" Value="70"/>
<Setter TargetName="SelectedDate1" Property="Label.TextColor" Value="#080808"/>
<Setter TargetName="SelectedDate2" Property="Label.TextColor" Value="#080808"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Frame
x:Name="SelectedFrame"
CornerRadius="5"
HasShadow="False"
Padding="0"
BackgroundColor="{AppThemeBinding Light=Gray, Dark=Gray}"
Margin="0"
VerticalOptions="CenterAndExpand"
WidthRequest="92"
HeightRequest="62">
<StackLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
Spacing="0">
<Label
x:Name="SelectedDate1"
Text="{Binding Day}"
FontSize="16"
Style="{StaticResource LightWhite}"
Margin="0,0,0,-2"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/>
<Label
x:Name="SelectedDate2"
Text="{Binding DayName}"
FontSize="20"
Style="{StaticResource BoldWhite}"
Margin="0,-2,0,0"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/>
</StackLayout>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Any help would be appreciated, thanks in advance.
This is a known bug with a PR open here. I'm hoping to merge this before the next release :)
You can already test this fix on your code and would love to ask you to do that so we can verify another scenario that is fixed. Let me know if you need the instructions for that.

Xamarin Community Toolkit LongpressCommand stops item selection in CollectionView iOS

The code works as expected in Android but in iOS works inconsistently. The selected label's border changes colour when tapped, sometimes. After 3 or four taps of different labels they cease to be selected at all. Long pressing a label works as expected, opening a different view. On returning to the view containing the CollectionView code attached, label selection has been re-enabled. The process then repeats itself.
I've tried changing Nuget versions of both Xamarin.Forms and Xamarin.Community.Toolkit(even the latest pre-release), xaml and code-behind to no avail.
I'm at a loss. Any help would be appreciated.
<CollectionView x:Name="categoryCollectionView"
ItemsSource="{Binding Categories,Mode=TwoWay}"
SelectionMode="Single"
SelectedItem="{Binding Category}"
SelectionChanged="OnMenuItemSelected"
Grid.Column="0"
HorizontalOptions="FillAndExpand"
Grid.ColumnSpan="8"
Grid.Row="3"
VerticalScrollBarVisibility="Always" >
<CollectionView.ItemsLayout>
<GridItemsLayout x:Name="CategoriesGridLayout"
Orientation="Vertical"
Span="3"
VerticalItemSpacing="2"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter TargetName="lblCategory" Property="Label.TextColor" Value="Red" />
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackLayout Orientation="Vertical"
VerticalOptions="Center"
xct:TouchEffect.LongPressCommand="{Binding LongPressCategoryCommand, Source={RelativeSource AncestorType={x:Type vm:CategoryVM}}}"
xct:TouchEffect.LongPressCommandParameter="{Binding CategoryString}" >
<StackLayout.Margin>
<OnPlatform x:TypeArguments="Thickness" iOS="2,2,4,4" Android="2" />
</StackLayout.Margin>
<Label x:Name="lblCategory"
Text="{Binding CategoryString}"
FontSize="Small"
BackgroundColor="#f5e2e1"
VerticalOptions="Center"
HorizontalOptions="CenterAndExpand"
WidthRequest="350"
Padding="5"
TextColor="#232F34"
LineBreakMode="TailTruncation"
Style="{DynamicResource CategoryLabelStyle}" >
<Label.Triggers>
<DataTrigger TargetType="Label"
Binding="{Binding Source={x:Reference fontSizeSwitch}, Path=IsToggled}"
Value="true">
<Setter Property="FontSize"
Value="Medium" />
<Setter Property="Padding"
Value="2" />
</DataTrigger>
</Label.Triggers>
</Label>
</StackLayout>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

Highlight Selected Item in CollectionView in Xamarin Forms

I am trying to hightlight selected item of collectionview with different color. The code works fine in iOS, but in Android it doesn't work. In Android, the first item is always selected but it doesn't hightlight the other items when I click them.
Update
I found the issue is GestureRecognizers on the Grid, If I remove that. It behavious as expected. After adding GestureRecognizers, the expected behavior is lost.
Workaround
If I wrap the Grid inside SwipeView, it works fine. However, the problem still remain when CollectionView has more than 100 items.
2nd Workaround
This worked nicely for any number of items in the CollectionView. Add second Grid inside the 1st Grid and apply GestureRecognizers event on the 2nd Grid and everythings works smoothly and as expected.
Theme.xaml -> getting styles from the theme file
<Style TargetType="Grid" x:Key="ItemTemplateGrid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState Name="Normal"/>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Dark={StaticResource BackgroundSecondaryColorDark}, Light={StaticResource BackgroundSecondaryColorLight}}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
XAML Page Resource
<DataTemplate x:Key="AndroidAyaItemTemplate">
<Grid RowDefinitions="*,Auto" Style="{DynamicResource ItemTemplateGrid}">
<Grid Grid.Row="0" RowDefinitions="Auto,Auto,Auto" RowSpacing="0" Padding="10">
<Label Grid.Row="0" LineBreakMode="WordWrap" IsVisible="{Binding BindingContext.ShowEnglishVerseNumber,
Source={x:Reference MyPage}, Converter={StaticResource InverterBooleanConverter}}">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding ArabicText.Aya}" FontSize="{Binding BindingContext.ActiveArabicFont.FontSize, Source={x:Reference MyPage}}"
FontFamily="{Binding BindingContext.ActiveArabicFont.FontPath, Source={x:Reference MyPage}}"/>
<Span Text="{Binding ArabicText.ArabicAyaNumber, StringFormat='﴿{0}﴾'}"
FontSize="{Binding BindingContext.ActiveArabicFont.FontSize, Source={x:Reference MyPage}}"
FontFamily="Sherzad"></Span>
</FormattedString>
</Label.FormattedText>
</Label>
<Label Grid.Row="0" LineBreakMode="WordWrap" IsVisible="{Binding BindingContext.ShowEnglishVerseNumber, Source={x:Reference MyPage}}">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding ArabicText.Aya}" FontSize="{Binding BindingContext.ActiveArabicFont.FontSize, Source={x:Reference MyPage}}"
FontFamily="{Binding BindingContext.ActiveArabicFont.FontPath, Source={x:Reference MyPage}}"/>
<Span Text="﴿" FontSize="35" FontFamily="Sherzad"></Span>
<Span Text="{Binding ArabicText.AyaNumber, Converter={StaticResource ZeroToEmptyConverter}}" FontSize="Small"></Span>
<Span Text="﴾" FontSize="35" FontFamily="Sherzad"></Span>
</FormattedString>
</Label.FormattedText>
</Label>
<Label Grid.Row="1" LineBreakMode="WordWrap" HorizontalTextAlignment="Start" Margin="0,5,0,5"
IsVisible="{Binding BindingContext.ShowTransliteration, Source={x:Reference MyPage}}"
FontSize="{Binding BindingContext.TransliterationFontSize, Source={x:Reference MyPage}}"
Text="{Binding ArabicText.Transliteration}"
FlowDirection="LeftToRight">
</Label>
<Label Grid.Row="2" LineBreakMode="WordWrap" HorizontalTextAlignment="Start"
IsVisible ="{Binding BindingContext.TranslationVisible, Source={x:Reference MyPage}}"
FontSize="{Binding BindingContext.ActiveTranslationFont.FontSize, Source={x:Reference MyPage}}"
FontFamily="{Binding BindingContext.ActiveTranslationFont.FontPath, Source={x:Reference MyPage}}"
Text="{Binding AyaTranslation}"
FlowDirection="{Binding BindingContext.ActiveTranslationLanguage.FlowDirection, Source={x:Reference MyPage}}"/>
</Grid>
<BoxView Grid.Row="1" Style="{DynamicResource HLine}" IsVisible="{Binding BindingContext.ShowHorizentalLine, Source={x:Reference MyPage}}"/>
<Grid.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="2" Command="{Binding BindingContext.ShareAyaCommand,Source={x:Reference itemView}}" CommandParameter="{Binding .}"/>
<SwipeGestureRecognizer Direction="Right" Command="{Binding BindingContext.NextChapterCommand, Source={x:Reference MyPage}}"/>
<SwipeGestureRecognizer Direction="Left" Command="{Binding BindingContext.PreviousChapterCommand, Source={x:Reference MyPage}}"/>
</Grid.GestureRecognizers>
</Grid>
</DataTemplate>
CollectionView
<CollectionView Grid.Row="0" ItemsSource="{Binding ArabicListText}" SelectedItem="{Binding SelectedAya}" SelectionMode="Single" FlowDirection="RightToLeft"
ItemTemplate="{StaticResource AndroidAyaItemTemplate}"
x:Name="itemView">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="5"/>
</CollectionView.ItemsLayout>
</CollectionView>
If I remove the style "ItemTemplateGrid" from the Grid, it highlights every row accordingly, but the color is the default color of OS.
There is no need for SwipeView. It should work without boths workarounds.
Since you had used the SelectedItem="{Binding SelectedAya}" , you could define a property in the model which bind the backgroundcolor of the DataTemplate so that you don't need to use style dictionary any more .
in your model
Add a property
private Color bgColor;
public Color BgColor
{
get => bgColor;
set
{
if (bgColor!= value)
{
bgColor= value;
foreach(YourModel model in ArabicListText)
{
if(mdoel == SelectedAya)
{
if(App.Current.RequestedTheme== OSAppTheme.Dark)
{
model.BgColor = xxx;
}
else
{
model.BgColor = xxx;
}
}
else
{
model.BgColor = xxx;
}
}
OnPropertyChanged(nameof(BgColor));
}
}
}
in DataTemplate
<Grid RowDefinitions="*,Auto" BackgroundColor="{Binding BgColor}" Padding="10">
in Code Behind(ViewModel)
private YourModel selectedAya;
public YourModel SelectedAya
{
get => selectedAya;
set
{
if (selectedAya!= value)
{
selectedAya= value;
OnPropertyChanged(nameof(SelectedAya));
}
}
}

Windows 7 Phone button with multiple textblocks

I have created a button in Blend by editing it's style. I added multiple text blocks with the intention of displaying data to the user in real time. However, I don't know how to interface with those text blocks in my code behind.
My Style XAML is this:
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="ButtonBackground" BorderThickness="{TemplateBinding BorderThickness}" Background="{StaticResource PhoneAccentBrush}" CornerRadius="0" Margin="8,12,12,12">
<TextBlock Margin="121,5,98,0" TextWrapping="Wrap" Text="Current Program:" Height="36" VerticalAlignment="Top"/>
</Border>
<TextBlock Margin="92,68,80,81" TextWrapping="Wrap" Text="" RenderTransformOrigin="0.265,0.51" HorizontalAlignment="Center" Width="271" x:Name="programName"/>
<TextBlock Height="32" Margin="21,0,16,12" TextWrapping="Wrap" Text="Date:" VerticalAlignment="Bottom" x:Name="CurrentDate"/>
</Grid>
</ControlTemplate>
My code to display the button is this:
<Grid x:Name="middleRow" Grid.Row="2">
<Button Content="Button" Margin="8,8,0,8" Style="{StaticResource ButtonCenter}" x:Name="Current" Click="Current_Click" d:LayoutOverrides="GridBox" />
</Grid>
In my code behind after the InitializeComponent(); I would like to change the ProgramName text block and the CurrentDate text block.
I'm thinking that I might have to create a control to do this but I'm not sure. My attempts at doing so failed (misc. errors). Can I access these text blocks in code? Please let me know.
UPDATE:
I wound up doing it like this:
<Button Margin="8,8,0,8" x:Name="Current" Click="Current_Click">
<Button.Content>
<StackPanel>
<TextBlock x:Name="ProgramName" Text="program name" HorizontalAlignment="Center" />
<TextBlock x:Name="CurrentDate" Text="current date" HorizontalAlignment="Center" />
</StackPanel>
</Button.Content>
</Button>
I applied my styles from the template in Blend and it appears to be working now.
You can't reference controls in a style by name as there could be multiple copies of them on a page.
If you made your button into a custom control you could make the text for the ProgramTitle and CurrentDate properties (which woudl be very easy to set).
Alternatively you could use databinding to set these values.

Resources