I'm currently working on a cross-platform app build with Xamarin Forms and I've several picker. I need to be sure all the pickers have a selected item, and if not I'd like to set their background to red.
I've already tried to loop to each element of the stacklayout to pick all Pickers and check their selected items but it's not working (it seems that my layout have only 2 children and no pickers). I cant't see how to do this with behavior too.
My loop (in code behind)
public void checkChampsVides()
{
for (int i = 0; i < DiagHabitat.Children.Count(); i++)
{
DisplayAlert("e", DiagHabitat.Children.GetHashCode().ToString(), "ok");
if (DiagHabitat.Children.ElementAt(i).GetType() == typeof(Picker))
{
Picker p = DiagHabitat.Children.ElementAt(i) as Picker;
if (p.SelectedIndex == 0)
p.BackgroundColor = Color.Red;
}
}
}
Xaml
<ContentPage
Title="Diagnostic Habitat"
Padding="20"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XXX.DiagnosticHabitatPage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key= "BoutonSauvegarde" TargetType="Button" >
<Setter Property="BackgroundColor" Value="#6AD0C6"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout x:Name="DiagHabitat">
<ProgressBar Progress="1"/>
<TableView x:Name ="DiagnosticHabitat" Intent="Form" HasUnevenRows="True">
<TableRoot Title="Diagnostic habitat">
<TableSection Title="Title1">
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" >
<Label VerticalOptions="Center" Text="text1"/>
<Picker x:Name="accesPorteEntree" HorizontalOptions="FillAndExpand" SelectedIndex="{Binding DiagHabitatAjoute.AccesPorteEntreeEPC, Mode=OneWayToSource}" >
<Picker.Items>
<x:String>Seuil haut</x:String>
<x:String>Seuil bas</x:String>
<x:String>Sans seuil</x:String>
</Picker.Items>
</Picker>
</StackLayout>
</ViewCell>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" >
<Label VerticalOptions="Center" Text="text2"/>
<Picker x:Name="niveauSecuAcces" HorizontalOptions="FillAndExpand" SelectedIndex="{Binding DiagHabitatAjoute.SecuAccesEPC, Mode=OneWayToSource}">
<Picker.Items>
<x:String>Bas</x:String>
<x:String>Moyen</x:String>
<x:String>Haut</x:String>
</Picker.Items>
</Picker>
</StackLayout>
</ViewCell>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" >
<Label VerticalOptions="Center" Text="Largeur circulation"/>
<Picker x:Name="largeurCirculation" HorizontalOptions="FillAndExpand" SelectedIndex="{Binding DiagHabitatAjoute.LargeurCircuEPC, Mode=OneWayToSource}" >
<Picker.Items>
<x:String>Inf à 75 cm</x:String>
<x:String>75 - 90 cm</x:String>
<x:String>Sup à 90 cm</x:String>
</Picker.Items>
</Picker>
</StackLayout>
</ViewCell>
...
You can use triggers, and apply them using implicit Style.
<TableView.Resources>
<ResourceDictionary>
<Style TargetType="Picker">
<Setter Property="BackgroundColor" Value="Green" />
<Style.Triggers>
<Trigger TargetType="Picker" Property="SelectedItem" Value="{x:Null}">
<Setter Property="BackgroundColor" Value="Red" />
</Trigger>
<Trigger TargetType="Picker" Property="SelectedIndex" Value="0">
<Setter Property="BackgroundColor" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</TableView.Resources>
You can recursively descend through your top most Layout container that holds the Pickers and use some switch pattern matching to determine when to recurse into the next container.
public void CheckPickers(Layout layout)
{
foreach (var child in layout.Children)
{
switch (child)
{
case Picker picker:
if (picker.SelectedIndex <= 0)
picker.BackgroundColor = Color.Red;
else
picker.BackgroundColor = Color.Green;
break;
case Layout l:
CheckPickers(l);
break;
default:
break;
}
}
}
Related
<CollectionView x:Name="nList" SelectionMode="Single" VerticalScrollBarVisibility="Always" SelectionChanged="OnMakingSelection" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<SwipeView>
<SwipeView.RightItems>
<SwipeItem Text="Delete" BackgroundColor="Red" Invoked="Delete_Btn" >
</SwipeItem>
</SwipeView.RightItems>
<StackLayout BackgroundColor="AntiqueWhite">
<Label Text="{Binding UserNotes}" TextColor="Black" FontFamily="PK" FontAttributes="Bold" FontSize="33" HorizontalOptions="Center"/>
<Label x:Name="loclabel" Text= "{Binding Location}" FontAttributes="Bold" TextColor="Black" HorizontalOptions="Center" />
<Button x:Name="mapbtnnn" Text="Open in Maps" FontFamily="PF" Clicked="Button_Clicked_Map" BackgroundColor="PowderBlue" CornerRadius="40" HorizontalOptions="Center"></Button>
<Image x:Name="Image" Source="{Binding Pic}" HeightRequest="90" ></Image>
<Label Text="*END OF NOTE*" FontAttributes="Bold" TextColor="Black" HorizontalOptions="Center"/>
</StackLayout>
</SwipeView>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Wanting to add colour to the selected item when sleceted.
Any tips,
I have tried a lot of steps online but none seem to work.
At the moment no colour is shown when selected
Wanting to add color to the selected item when selected.
You could use visual-state-manager to change the color of selected item,set swip background color as white, and add VisualStateManager.VisualStateGroups for swip like below:
<CollectionView x:Name="nList" SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView BackgroundColor="White">
<SwipeView.RightItems>
<SwipeItem Text="Delete" BackgroundColor="Red" >
</SwipeItem>
</SwipeView.RightItems>
<StackLayout Padding="5" Orientation="Vertical">
<Label LineBreakMode="WordWrap" Text="{Binding Name}" />
</StackLayout>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal" />
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Yellow" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
Code behind:
public partial class Page1 : ContentPage
{
public Page1()
{
InitializeComponent();
nList.ItemsSource = new List<Contact>
{
new Contact("JP Morgan"),
new Contact("Andrew Carnegie"),
new Contact("Steve Jobs")
};
}
}
public class Contact
{
public string Name { get; set; }
public Contact(string name)
{
Name = name;
}
}
I am trying to make a tabs like view with plain xamarin forms because I don't want to use any third party plugin. For that I used two frames like below and changed its state as "Selected" & "Unselected" when tapped on that frame to make it look like that.
Style for frame:
<Style TargetType="Frame">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Orange" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="UnSelected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
My Frame:
<Frame x:Name="AllNewsTab" Padding="10,5,10,5" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
<Label Text="All" FontFamily="{StaticResource BoldFont}" TextColor="{StaticResource BodyTextColor}" FontSize="Medium" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
</Frame.GestureRecognizers>
</Frame>
Tapped Event:
private void Tab_Tapped(object sender, EventArgs e)
{
if (frameSelected != null)
VisualStateManager.GoToState(frameSelected, "UnSelected");
VisualStateManager.GoToState((Frame)sender, "Selected");
frameSelected = (Frame)sender;
}
But I want one frame to look selected when the page appears for the first time. So I tried to do like this in the pages OnAppearing Method. But it doesn't work.
What is the problem here?
protected override void OnAppearing()
{
VisualStateManager.GoToState(AllNewsTab, "Selected");
base.OnAppearing();
}
Try this,
In xamarin, VisualElement have 4 states such as Normal, Disabled, Focused, Selected.
And we can define our own VisualElements.
MainPage.Xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Xam_VS_Test.Views.MainPage">
<ContentPage.Resources>
<Style TargetType="Frame">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="SelectionStates">
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Orange" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="UnSelected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Orientation="Vertical" >
<Frame x:Name="AllNewsTab" Padding="10,5,10,5" HeightRequest="20" WidthRequest="50" HorizontalOptions="FillAndExpand" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
<Label Text="All" FontSize="Large" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
</Frame.GestureRecognizers>
</Frame>
<Frame x:Name="AllNewsTab2" Padding="10,5,10,5" HeightRequest="20" WidthRequest="50" HorizontalOptions="FillAndExpand" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
<Label Text="1" FontSize="Large" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
</Frame.GestureRecognizers>
</Frame>
<Frame x:Name="AllNewsTab3" Padding="10,5,10,5" HeightRequest="20" WidthRequest="50" HorizontalOptions="FillAndExpand" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
<Label Text="2" FontSize="Large" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
</Frame.GestureRecognizers>
</Frame>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MainPage.cs
public partial class MainPage : ContentPage
{
Frame frameSelected;
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
if (frameSelected == null)
{
VisualStateManager.GoToState(AllNewsTab, "Selected");
frameSelected = AllNewsTab;
}
base.OnAppearing();
}
private void Tab_Tapped(object sender, EventArgs e)
{
if (frameSelected != null)
VisualStateManager.GoToState(frameSelected, "UnSelected");
VisualStateManager.GoToState((Frame)sender, "Selected");
frameSelected = (Frame)sender;
}
}
I have a xamarin.forms app that supports RTL, but when i convert a Page to RTL the NavigationPage.TitleView text disapears.
The NavigationPage.TitleView Code:
<NavigationPage.TitleView>
<Label Text="{Binding Title}" Style="{StaticResource TittleLabel}" HorizontalTextAlignment="Start" HorizontalOptions="Start" VerticalOptions="CenterAndExpand"></Label>
</NavigationPage.TitleView>
This is the Result screen.
Thanks in Advance.
For RTL, the Label having RTL issues. Please find the issue link below.
https://github.com/xamarin/Xamarin.Forms/issues/3611
When setting RTL to Page, the title view is disappeared. you can report to the Xamarin team. For instead of setting a title through Label, directly setting title property of ContentPage like below,
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="RTL"
FlowDirection="RightToLeft">
It's working but RTL is not applying. But the title is displayed. You can report this issue also.
I guess maybe the binding do not work. I make a sample for your reference.
MainPage.xaml
<StackLayout>
<Button Clicked="Button_Clicked" Text="Title View Page" />
</StackLayout>
MainPage.xaml.cs
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new TitleViewPage());
}
TitleViewPage.xaml
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="TittleLabel" TargetType="Label">
<Setter Property="TextColor" Value="Green" />
<Setter Property="FontSize" Value="Large" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<NavigationPage.TitleView>
<StackLayout>
<Label
HorizontalOptions="Start"
HorizontalTextAlignment="Start"
Style="{StaticResource TittleLabel}"
Text="{Binding Title}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</NavigationPage.TitleView>
<ContentPage.Content>
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to TitleView Page!"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
TitleViewPage.xaml.cs
public string Title { get; set; }
public TitleViewPage()
{
InitializeComponent();
Title = "My TitleView";
this.BindingContext = this;
}
App.xaml.cs
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
Updated:
When you set the FlowDirection to RightToLeft, the titleview could be seen on horizontal screen.
On the Right-to-left localization document, it lists the limitations.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/localization/right-to-left
NavigationPage button location, toolbar item location, and transition animation is controlled by the device locale, rather than the FlowDirection property.
This question has also be reported. You could follow the update . https://github.com/xamarin/Xamarin.Forms/issues/9083
this aproach worked for me:
-set RTL-FlowDirection for main-layout (wrapper) of ContentPage's content (instead of ContentPage)
App.xaml
<Application.Resources>
<ResourceDictionary>
<Style x:Key="PageTitleStyle" TargetType="Label">
<Setter Property="HorizontalOptions" Value="EndAndExpand"/>
<Setter Property="Padding" Value="0,0,5,0"/>
</Style>
</ResourceDictionary>
</Application.Resources>
MainPage.xaml
<ContentPage ....>
<NavigationPage.TitleView >
<Label Text="{Binding Title}" Style="{StaticResource PageTitleStyle}" />
</NavigationPage.TitleView>
<StackLayout FlowDirection="RightToLeft">
....
</StackLayout>
</ContentPage>
This template takes as a binding parameter HeaderHeight. Is there a way that I can make HeaderHeight ignored by the StackLayout if it's not specified in the XAML that calls the template?
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Japanese;assembly=Japanese" x:Class="Japanese.Templates.HeaderTemplate" x:Name="this">
<ContentView.Triggers>
<Trigger TargetType="local:Templates.HeaderTemplate" Property="HeaderType" Value="Custom">
<Setter Property="Content">
<Setter.Value>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Vertical" Spacing="0" Margin="0">
<StackLayout HeightRequest="{Binding HeaderHeight, Source={x:Reference this}}" Orientation="Vertical" Spacing="0" Margin="0" >
<Label Text="ABC" HorizontalOptions="Start" VerticalOptions="EndAndExpand" />
</StackLayout>
</StackLayout>
</Setter.Value>
</Setter>
</Trigger>
</ContentView.Triggers>
</ContentView>
You can set the default value of HeaderHeight to -1
The UI should go back to normal
HeaderHeight = -1;
Once it's a BindableProperty, it should look like this:
public static readonly BindableProperty HeaderHeightProperty = BindableProperty.Create(nameof(HeaderHeight), typeof(double), typeof(HeaderTemplate), -1);
public double HeaderHeight
{
get => (double)GetValue(HeaderHeightProperty);
set => SetValue(HeaderHeightProperty, value);
}
this is my ListBox:
XMLA:
<Style x:Key="ListBoxStyle" TargetType="ListBox">
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="ScrollViewer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="{TemplateBinding Height}"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<ItemsPresenter Grid.Row="0"/>
<Button Content="Add" Grid.Row="1" Click="Button_Click"/>
</Grid>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <ListBox Style="{StaticResource ListBoxStyle}" Name="listBox" Height="600" ItemsSource="{Binding MyData}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<Image Source="{Binding Img}" Stretch="UniformToFill"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-Behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 50; i++)
{
MyData.Add(new Data { Name = i.ToString(), Img = "/Background.png" });
}
}
When I Click Button more, I get a OutOfMemoryException.
but,If I don't set ListBox Style. I add Items into ListBox,the Project is Work.
When you retemplate the ListBox, you lose data virtualization. So, all your item images are in memory all the time. Can you decrease the size of the images to avoid high memory consumption?
I suppose, to enable virtualization you should change ListBox ControlTemplate. Move all except of ItemsPresenter out of ScrollViewer:
<ControlTemplate TargetType="ListBox">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<ScrollViewer x:Name="ScrollViewer" Grid.Row="0">
<ItemsPresenter />
</ScrollViewer>
<Button Content="Add" Grid.Row="1" Click="Button_Click"/>
</Grid>
</ControlTemplate>
And make sure that your MyData implements IList interface.