CheckBox values / no MVVM Xamarin - xamarin

I have a group of check boxes and i need them to change value.. if one is checked the other should be unchecked. The reason why dont want to implement MVVM is that this is just new frontend for already existing application, i just need these to work before we merge projects. This what i have and it doesnt work,i get null reference / System.NullReferenceException: 'Object reference not set to an instance of an object.'
I have this in my code
private void AdvancedCheckBox_IsCheckedChanged(object sender, IsCheckedChangedEventArgs e)
{
if (AdvancedCheckBox.IsChecked == true) //System.NullReferenceException: 'Object reference not set to an instance of an object.'
{
AllCheckBox.IsChecked = false;
UpperIntermediateCheckBox.IsChecked = false;
AdvancedCheckBox.IsChecked = false;
}
else
AdvancedCheckBox.IsChecked = true;
}
private void UpperIntermediateCheckBox_IsCheckedChanged(object sender, IsCheckedChangedEventArgs e)
{
if (UpperIntermediateCheckBox.IsChecked == true)
{
AllCheckBox.IsChecked = false;
UpperIntermediateCheckBox.IsChecked = false;
AdvancedCheckBox.IsChecked = false;
}
else
UpperIntermediateCheckBox.IsChecked = true;
}
private void IntermediateCheckBox_IsCheckedChanged(object sender, IsCheckedChangedEventArgs e)
{
CheckBox IntermediateCheckBox = sender as CheckBox;
if (IntermediateCheckBox.IsChecked == false)
{
AllCheckBox.IsChecked = false;
UpperIntermediateCheckBox.IsChecked = false;
AdvancedCheckBox.IsChecked = false ;
}
else
IntermediateCheckBox.IsChecked = true ;
}
private void AllCheckBox_IsCheckedChanged(object sender, IsCheckedChangedEventArgs e)
{
CheckBox AllCheckBox = sender as CheckBox;
if (AllCheckBox.IsChecked == true) System.NullReferenceException: 'Object reference not set to an instance of an object.'
{
UpperIntermediateCheckBox.IsChecked = false;
AdvancedCheckBox.IsChecked = false;
IntermediateCheckBox.IsChecked = false;
}
else
AllCheckBox.IsChecked = true;
}
and my xaml
<StackLayout Grid.Row="0"
Orientation="Horizontal"
Spacing="10"
HorizontalOptions="Start">
<grial:Checkbox x:Name="AllCheckBox"
IsCheckedChanged ="AllCheckBox_IsCheckedChanged"
HorizontalOptions="Start">
<Label
Margin="10,0"
FontSize="19"
Text="{ grial:Translate A_LabelAllArticles}"
VerticalOptions="Center"
TextColor="{ DynamicResource AccentColor }" />
</grial:Checkbox>
</StackLayout>
<StackLayout Grid.Row="1"
Orientation="Horizontal"
Spacing="10"
HorizontalOptions="Start">
<grial:Checkbox x:Name="BeginnerCheckBox"
IsChecked="false"
HorizontalOptions="Start">
<Label
FontSize="19"
Margin="10,0"
Text="{ grial:Translate A_LabelBeginnerArticles}"
VerticalOptions="Center"
TextColor="{ DynamicResource AccentColor }" />
</grial:Checkbox>
</StackLayout>
<StackLayout Grid.Row="2"
Orientation="Horizontal"
Spacing="10"
HorizontalOptions="Start">
<grial:Checkbox x:Name="IntermediateCheckBox"
IsCheckedChanged="IntermediateCheckBox_IsCheckedChanged"
HorizontalOptions="Start">
<Label
FontSize="19"
Margin="10,0"
Text="{ grial:Translate A_LabelIntermediateArticles}"
VerticalOptions="Center"
TextColor="{ DynamicResource AccentColor }" />
</grial:Checkbox>
</StackLayout>
<StackLayout Grid.Row="3"
Orientation="Horizontal"
Spacing="10"
HorizontalOptions="Start">
<grial:Checkbox x:Name="UpperIntermediateCheckBox"
IsCheckedChanged="UpperIntermediateCheckBox_IsCheckedChanged"
HorizontalOptions="Start">
<Label
FontSize="19"
Margin="10,0"
Text="{ grial:Translate A_LabelUpperIntermediateArticles}"
VerticalOptions="Center"
TextColor="{ DynamicResource AccentColor }" />
</grial:Checkbox>
</StackLayout>
<StackLayout Grid.Row="4"
Orientation="Horizontal"
Spacing="10"
HorizontalOptions="Start">
<grial:Checkbox x:Name="AdvancedCheckBox"
IsCheckedChanged="AdvancedCheckBox_IsCheckedChanged"
HorizontalOptions="Start">
<Label
FontSize="19"
Margin="10,0"
Text="{ grial:Translate A_LabelAdvancedArticles}"
VerticalOptions="Center"
TextColor="{ DynamicResource AccentColor }" />
</grial:Checkbox>

You are using a Checkbox from the Grial UIKit, but are defining the sender as the Native Xamarin.Forms CheckBox, use the Grial CheckBox as the Casting Class of the sender
//This will make every checkbox to checked or unchecked depending of the state of the clicked one
private void AllCheckBox_IsCheckedChanged(object sender, IsCheckedChangedEventArgs e)
{
CheckBox ClickedCheckbox = sender as UXDivers.Grial.Checkbox;
ChangeAllCheckboxesTo(ClickedCheckbox.IsChecked != null ? ClickedCheckbox.IsChecked : false);
}
//This will make every checkbox to false if you select one
private void AnyCheckBox_IsCheckedChanged(object sender, IsCheckedChangedEventArgs e)
{
CheckBox ClickedCheckbox = sender as UXDivers.Grial.Checkbox;
bool WasSelected = ClickedCheckbox.IsChecked != null ? ClickedCheckbox.IsChecked != null : false;
ChangeAllCheckboxesTo(false);
if(!WasSelected)
ClickedCheckbox.IsChecked = true;
}
public void ChangeAllCheckboxesTo(bool value)
{
try
{
UpperIntermediateCheckBox.IsChecked = value;
AdvancedCheckBox.IsChecked = value;
IntermediateCheckBox.IsChecked = value;
}
catch(Exception ex)
{
}
}

Related

PropertyChanged Event doesn't reflect new Image.Source on first run

I'm working on mobile app that kinda simulates how to build a Desktop Computer by dragging and dropping an image in order. I work with DropGestureRecognizer with AllowDrop set to True for the Drop Zone Image controls and DragGestureRecognizer with CanDrag set to True for the Drag Image Objects.
The idea is the Drag Image Objects will get dragged and dropped to a Drop Zone Image Control and if they dropped the correct Drag Image, the Drop Zone will accept this as the Image.Source and another Drop Zone will be stacked in front of it to work with the next Desktop Computer component. Otherwise, it would get rejected and the Image.Source will be set to empty or null.
However, i'm encountering a weird issue that, on the first incorrect image dragged, the Image.Source gets reset to empty or null by property but on the actual UI, it doesn't. On the succeeding EventHandler execution, it does get reset. I have a TapGestureRecognizer on the Drop Zone to check if there is an Image.Source set or not.
I'm sorry if my explanation is a bit confusing because English is not my native language and i'm having a hard time explaining it. So please refer to below example in GIF and my code:
View (.xaml):
<ContentPage.Content>
<Grid RowDefinitions="Auto,60,*"
ColumnDefinitions="*">
<RelativeLayout Grid.Row="0" Grid.Column="0" HorizontalOptions="Center">
<Image x:Name="imgCaseDropZone"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
HeightRequest="{Binding ScreenWidth}"
WidthRequest="{Binding ScreenWidth}"
PropertyChanged="CaseDropZone_PropertyChanged"
BackgroundColor="LightGray">
<Image.GestureRecognizers>
<DropGestureRecognizer AllowDrop="True" />
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
</Image.GestureRecognizers>
</Image>
</RelativeLayout>
<Label Grid.Row="1" Grid.Column="0"
x:Name="lblDirections"
Text="Directions: Drag the components below in its proper order to the drop zone above."
TextColor="Black"
Padding="10"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<ScrollView Grid.Row="2"
Orientation="Horizontal"
Margin="5">
<StackLayout Orientation="Horizontal">
<!--#region Case -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding CaseIsVisible}">
<Image Grid.Row="0"
x:Name="imgCaseDragObject"
Source="{Binding CaseImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding CaseLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Case Cover -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding CaseCoverIsVisible}">
<Image Grid.Row="0"
Source="{Binding CaseCoverImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding CaseCoverLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Case Screw -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding CaseScrewIsVisible}">
<Image Grid.Row="0"
Source="{Binding CaseScrewImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding CaseScrewLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Hard Disk Drive -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding HardDiskDriveIsVisible}">
<Image Grid.Row="0"
Source="{Binding HardDiskDriveImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding HardDiskDriveLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Heatsink -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding HeatsinkIsVisible}">
<Image Grid.Row="0"
Source="{Binding HeatsinkImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding HeatsinkLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Memory Module -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding MemoryModuleIsVisible}">
<Image Grid.Row="0"
Source="{Binding MemoryModuleImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding MemoryModuleLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Motherboard -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding MotherboardIsVisible}">
<Image Grid.Row="0"
Source="{Binding MotherboardImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding MotherboardLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Motherboard Screw -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding MotherboardScrewIsVisible}">
<Image Grid.Row="0"
Source="{Binding MotherboardScrewImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding MotherboardScrewLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Power Supply -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding PowerSupplyIsVisible}">
<Image Grid.Row="0"
Source="{Binding PowerSupplyImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding PowerSupplyLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
<!--#region Processor -->
<Grid RowDefinitions="*,Auto"
IsVisible="{Binding ProcessorIsVisible}">
<Image Grid.Row="0"
Source="{Binding ProcessorImgSource}">
<Image.GestureRecognizers>
<DragGestureRecognizer CanDrag="True" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Row="1"
Text="{Binding ProcessorLabel}"
TextColor="White"
FontSize="Medium"
BackgroundColor="Gray"
HorizontalTextAlignment="Center" />
</Grid>
<!--#endregion-->
</StackLayout>
</ScrollView>
</Grid>
</ContentPage.Content>
View Code (.xaml.cs):
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AssemblyPage : ContentPage
{
string caseSource;
public AssemblyPage()
{
InitializeComponent();
}
int dragCount = 0;
private void CaseDropZone_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Source")
{
caseSource = imgCaseDropZone.Source.ToString().Split(':').Last().Trim();
if (string.IsNullOrEmpty(caseSource))
{
return;
}
if (caseSource != "img_assembly_case.png")
{
imgCaseDropZone.Source = string.Empty;
lblDirections.Text = $"Drag Count: {++dragCount}";
}
}
}
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
Application.Current.MainPage.DisplayAlert("", $"{imgCaseDropZone.Source}", "OK");
}
}
ViewModel (.cs):
public class AssemblyViewModel : BaseVM
{
public double ScreenWidth => Xamarin.Forms.Application.Current.MainPage.Width;
#region Case
bool caseIsVisible;
public bool CaseIsVisible
{
get => caseIsVisible;
set => SetProperty(ref caseIsVisible, value);
}
public string CaseImgSource { get; }
public string CaseLabel { get; }
#endregion
#region CaseCover
bool caseCoverIsVisible;
public bool CaseCoverIsVisible
{
get => caseCoverIsVisible;
set => SetProperty(ref caseCoverIsVisible, value);
}
public string CaseCoverImgSource { get; }
public string CaseCoverLabel { get; }
#endregion
#region HardDiskDrive
bool hardDiskDriveIsVisible;
public bool HardDiskDriveIsVisible
{
get => hardDiskDriveIsVisible;
set => SetProperty(ref hardDiskDriveIsVisible, value);
}
public string HardDiskDriveImgSource { get; }
public string HardDiskDriveLabel { get; }
#endregion
#region CaseScrew
bool caseScrewIsVisible;
public bool CaseScrewIsVisible
{
get => caseScrewIsVisible;
set => SetProperty(ref caseScrewIsVisible, value);
}
public string CaseScrewImgSource { get; }
public string CaseScrewLabel { get; }
#endregion
#region Heatsink
bool heatsinkIsVisible;
public bool HeatsinkIsVisible
{
get => heatsinkIsVisible;
set => SetProperty(ref heatsinkIsVisible, value);
}
public string HeatsinkImgSource { get; }
public string HeatsinkLabel { get; }
#endregion
#region MemoryModule
bool memoryModuleIsVisible;
public bool MemoryModuleIsVisible
{
get => memoryModuleIsVisible;
set => SetProperty(ref memoryModuleIsVisible, value);
}
public string MemoryModuleImgSource { get; }
public string MemoryModuleLabel { get; }
#endregion
#region Motherboard
bool motherboardIsVisible;
public bool MotherboardIsVisible
{
get => motherboardIsVisible;
set => SetProperty(ref motherboardIsVisible, value);
}
public string MotherboardImgSource { get; }
public string MotherboardLabel { get; }
#endregion
#region MotherboardScrew
bool motherboardScrewIsVisible;
public bool MotherboardScrewIsVisible
{
get => motherboardScrewIsVisible;
set => SetProperty(ref motherboardScrewIsVisible, value);
}
public string MotherboardScrewImgSource { get; }
public string MotherboardScrewLabel { get; }
#endregion
#region PowerSupply
bool powerSupplyIsVisible;
public bool PowerSupplyIsVisible
{
get => powerSupplyIsVisible;
set => SetProperty(ref powerSupplyIsVisible, value);
}
public string PowerSupplyImgSource { get; }
public string PowerSupplyLabel { get; }
#endregion
#region Processor
bool processorIsVisible;
public bool ProcessorIsVisible
{
get => processorIsVisible;
set => SetProperty(ref processorIsVisible, value);
}
public string ProcessorImgSource { get; }
public string ProcessorLabel { get; }
#endregion
public AssemblyViewModel()
{
CaseIsVisible = true;
CaseImgSource = "img_assembly_case.png";
CaseLabel = "Case";
CaseCoverIsVisible = true;
CaseCoverImgSource = "img_assembly_case_cover.png";
CaseCoverLabel = "Case Cover";
CaseScrewIsVisible = true;
CaseScrewImgSource = "img_assembly_case_screw.png";
CaseScrewLabel = "Case Screw";
HardDiskDriveIsVisible = true;
HardDiskDriveImgSource = "img_assembly_hard_disk_drive.png";
HardDiskDriveLabel = "Hard Disk Drive";
HeatsinkIsVisible = true;
HeatsinkImgSource = "img_assembly_heat_sink.png";
HeatsinkLabel = "Heatsink";
MemoryModuleIsVisible = true;
MemoryModuleImgSource = "img_assembly_memory_module.png";
MemoryModuleLabel = "Memory Module";
MotherboardIsVisible = true;
MotherboardImgSource = "img_assembly_motherboard.png";
MotherboardLabel = "Motherboard";
MotherboardScrewIsVisible = true;
MotherboardScrewImgSource = "img_assembly_motherboard_screw.png";
MotherboardScrewLabel = "Motherboard Screw";
PowerSupplyIsVisible = true;
PowerSupplyImgSource = "img_assembly_power_supply.png";
PowerSupplyLabel = "Power Supply";
ProcessorIsVisible = true;
ProcessorImgSource = "img_assembly_processor.png";
ProcessorLabel = "Processor";
}
}
Current Build demo in GIF: https://imgur.com/a/oLeM9DV (i can't directly link the GIF because its too big)
Because when you trigger the PropertyChanged event, the drag and drop action has already been completed and the image has been automatically set to the target.
We could make that judgment as soon as we drag it over the target with DragOver event.Then make an action when the drag and drop is complete with Drop event.
For example,change the codes of the Image (imgCaseDropZone):
<Image x:Name="imgCaseDropZone"
RelativeLayout.XConstraint="0"
RelativeLayout.YConstraint="0"
RelativeLayout.WidthConstraint="400"
RelativeLayout.HeightConstraint="400"
BackgroundColor="LightGray"
>
<Image.GestureRecognizers>
<DropGestureRecognizer AllowDrop="{Binding CaseIsVisible}" DragOver="CaseDropZone_DragOver" Drop="CaseDropZone_Drop"/>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped" />
</Image.GestureRecognizers>
</Image>
in the code behind:
private void CaseDropZone_DragOver(object sender, DragEventArgs e)
{
FileImageSource file = (FileImageSource)e.Data.Image;
string name = file.File;
if (name != "img_assembly_case.png")
{
e.Data.Image = string.Empty; // set the value string.Empty when drag it over the target,then it will fill the empty source to the image.
}
}
private async void CaseDropZone_Drop(object sender, DropEventArgs e)
{
var ctx = (BindingContext as AssemblyViewModel);
FileImageSource source = (FileImageSource)await e.Data.GetImageAsync();
string name = source.File;
if (name == "img_assembly_case.png")
{
ctx.CaseIsVisible = false;
imgMotherboardDropZone.IsVisible = true;
}
else
{
Global.Score.PCAssembly -= 5;
DisplayAlert($"Score: {Global.Score.PCAssembly}", "The pre-requisite component for this part has not yet been placed.", "OK");
}
}
Other Images are modified like this.

Collectionview is broken when I change grid

I have a list where can be one or more than grid. I am trying to use collectionview for this. But when I change grid, view of some collectionview items are broken (on iOS app). As in gif:
But when I swipe scroll, broken grids are getting better. My project is custom project. That's why I can't share sample app. But collectionview implementation is as follows:
<RefreshView Command="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}">
<CollectionView x:Name="FlowListFileFolder"
AutomationId="FileSystemPage_MainScreenListView"
IsGrouped="true"
ItemsSource="{Binding FlowListCloudItem}"
ItemsLayout="{Binding CollectionViewItemsLayout}">
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<StackLayout Style="{DynamicResource FlowListGroupTitleWrapperStyle}">
<Label Text="{Binding Path=Key}"
Style="{DynamicResource FlowListGroupTitleStyle}" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate>
<local:ItemGridView LongPressEvent="Handle_LongPressEvent" SingleTapEvent="Handle_TappedEvent">
<local:CustomFolderFrame Style="{DynamicResource FspCiFrameWrapperStyle}" BorderColor="{Binding FrameColor}">
<StackLayout Orientation="Vertical" Spacing="0" BackgroundColor="{Binding FrameColor}" Margin="1">
<Grid Style="{Binding FspCi_GridStyle}">
<StackLayout AutomationId="FileSystemPage_FolderStackLayout"
Style="{DynamicResource FspCiGeneralWrapperLayoutStyle}">
<StackLayout Style="{Binding FspCiThumbnailImageAndInformation_GeneralWrapperLayoutStyle}">
<StackLayout Style="{Binding FspCiThumbnailImage_WrapperLayoutStyle}">
<ff:CachedImage AutomationId="{Binding LvItemThumbnailSource, StringFormat='FolderIcon_{0}'}"
Style="{Binding FspCiFolderThumbnailImageStyle}" />
<ff:CachedImage Style="{Binding FspCiFileThumbnailImageStyle}" />
</StackLayout>
<StackLayout Style="{Binding FspCiCloudItemInformation_WrapperLayoutStyle}">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" Spacing="5">
<Label AutomationId="FileSystemPage_lblDisplayNameFolder"
Text="{Binding DisplayName}"
Style="{DynamicResource FspCiDisplayNameStyle}" />
<ff:CachedImage Source="group.png" Style="{Binding FspCiGroupIcon_ImageStyle}" />
</StackLayout>
<Label Text="{Binding CreationDate}"
Style="{DynamicResource FspCiCreationDateStyle}" />
</StackLayout>
</StackLayout>
</StackLayout>
<StackLayout Style="{Binding FspCiCheckUncheckMoreDetail_WrapperLayoutStyle}">
<StackLayout Style="{Binding FspCiCheck_StackLayoutStyle}">
<ff:CachedImage AutomationId="{Binding DisplayName, StringFormat='FileSystemPage_{0}_checked'}"
Source="checked.png"
Style="{Binding FspCiCheckUncheck_ImageStyle}" />
</StackLayout>
<StackLayout Style="{Binding FspCiUncheck_StackLayoutStyle}">
<ff:CachedImage AutomationId="{Binding DisplayName, StringFormat='FileSystemPage_{0}_unchecked'}"
Source="unchecked.png"
Style="{Binding FspCiCheckUncheck_ImageStyle}" />
</StackLayout>
<StackLayout Style="{Binding FspCiMoreDetail_StackLayoutStyle}">
<ff:CachedImage AutomationId="FileSystemPage_ItemMoreDetail"
Source="ic_dots_gray.png"
Style="{Binding FspCiCheckUncheck_ImageStyle}"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="ItemMoreDetail_Clicked" />
</StackLayout.GestureRecognizers>
</StackLayout>
</StackLayout>
</Grid>
</StackLayout>
</local:CustomFolderFrame>
</local:ItemGridView>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.Footer>
<StackLayout Style="{DynamicResource FspCiFooterWrapperLayoutStyle}">
<Label Text="{Binding LabelFolderCount}"
Style="{DynamicResource FspCiFooterFileFolderCountStyle}" />
<Label Text="{Binding LabelFileCount}"
Style="{DynamicResource FspCiFooterFileFolderCountStyle}" />
</StackLayout>
</CollectionView.Footer>
</CollectionView>
</RefreshView>
For supporting different screens with one project, I had used different styles that changes according to device's viewport information. When app open, I gets device's viewport information and I set style that is suitable viewport. These styles gets from there.
And when I click grid button, I change some of these styles as follow:
public class FileSystemViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingField, value))
return;
backingField = value;
OnPropertyChanged(propertyName);
}
private ItemsLayout collectionViewItemsLayout;
public ItemsLayout CollectionViewItemsLayout { get => collectionViewItemsLayout; set { SetValue(ref collectionViewItemsLayout, value); } }
public Command GridClicked()
{
var btnGrid_Clicked = new Command(
async () => {
if (FlowListGridCount == 1)
{
UpdateMultipleGrid();
}
else
{
UpdateOneGrid();
}
});
return btnGrid_Clicked;
}
public void UpdateMultipleGrid()
{
foreach (var item in CloudItemList[0])
{
SetFolderTwoGridView(item);
}
foreach (var item in CloudItemList[1])
{
SetFileTwoGridView(item);
}
Helpers.Settings.FlowColumnCount = FlowListGridCount = ElementResolutionsHelper.GetPageFolderColumnCount(); //GetPageFolderColumnCount returns column count that is suitable with screen
CollectionViewItemsLayout = new GridItemsLayout(FlowListGridCount, ItemsLayoutOrientation.Vertical);
}
public void UpdateOneGrid()
{
foreach (var item in CloudItemList[0])
{
SetFolderOneGridView(item);
}
foreach (var item in CloudItemList[1])
{
SetFileOneGridView(item);
}
Helpers.Settings.FlowColumnCount = FlowListGridCount = ElementResolutionsHelper.GetPageFolderColumnCount(); //GetPageFolderColumnCount returns 1 for this situation
CollectionViewItemsLayout = new GridItemsLayout(FlowListGridCount, ItemsLayoutOrientation.Vertical);
}
private void SetFolderTwoGridView(CloudItemViewingResponse item)
{
if (item.IsShared)
item.LvItemThumbnailSource = "folder_share.png";
else
item.LvItemThumbnailSource = "ic_folder.png";
item.FspCiCheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCheck_StackLayoutStyle"]);
item.FspCiUncheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridUncheck_StackLayoutStyle"]);
item.FspCiMoreDetail_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridMoreDetail_StackLayoutStyle"]);
item.FspCiCheckUncheck_ImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCheckUncheckMoreDetail_ImageStyle"]);
item.FspCiCheckUncheckMoreDetail_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCheckUncheckMoreDetail_WrapperLayoutStyle"]);
item.FspCiCloudItemInformation_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCloudItemInformation_WrapperLayoutStyle"]);
item.FspCiThumbnailImage_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFolderThumbnailImage_WrapperLayoutStyle"]);
item.FspCiFolderThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFolderThumbnailImageStyle"]);
item.FspCiFileThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFileThumbnailImageStyle"]);
item.FspCiThumbnailImageAndInformation_GeneralWrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridThumbnailImageAndInformation_GeneralWrapperLayoutStyle"]);
item.FspCi_GridStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFolder_GridStyle"]);
}
private void SetFileTwoGridView(CloudItemViewingResponse item)
{
item.FspCiCheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCheck_StackLayoutStyle"]);
item.FspCiUncheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridUncheck_StackLayoutStyle"]);
item.FspCiMoreDetail_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridMoreDetail_StackLayoutStyle"]);
item.FspCiCheckUncheck_ImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCheckUncheckMoreDetail_ImageStyle"]);
item.FspCiCheckUncheckMoreDetail_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCheckUncheckMoreDetail_WrapperLayoutStyle"]);
item.FspCiCloudItemInformation_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridCloudItemInformation_WrapperLayoutStyle"]);
item.FspCiThumbnailImage_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFileThumbnailImage_WrapperLayoutStyle"]);
item.FspCiFolderThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFolderThumbnailImageStyle"]);
item.FspCiFileThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFileThumbnailImageStyle"]);
item.FspCiThumbnailImageAndInformation_GeneralWrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridThumbnailImageAndInformation_GeneralWrapperLayoutStyle"]);
item.FspCi_GridStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiMultipleGridFile_GridStyle"]);
}
private void SetFolderOneGridView(CloudItemViewingResponse item)
{
if (item.IsShared)
item.LvItemThumbnailSource = "folder_share.png";
else
item.LvItemThumbnailSource = "ic_folder.png";
item.FspCiCheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCheck_StackLayoutStyle"]);
item.FspCiUncheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridUncheck_StackLayoutStyle"]);
item.FspCiMoreDetail_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridMoreDetail_StackLayoutStyle"]);
item.FspCiCheckUncheck_ImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCheckUncheckMoreDetail_ImageStyle"]);
item.FspCiCheckUncheckMoreDetail_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCheckUncheckMoreDetail_WrapperLayoutStyle"]);
item.FspCiCloudItemInformation_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCloudItemInformation_WrapperLayoutStyle"]);
item.FspCiThumbnailImage_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridThumbnailImage_WrapperLayoutStyle"]);
item.FspCiFolderThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridFolderThumbnailImageStyle"]);
item.FspCiFileThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridFileThumbnailImageStyle"]);
item.FspCiThumbnailImageAndInformation_GeneralWrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridThumbnailImageAndInformation_GeneralWrapperLayoutStyle"]);
item.FspCi_GridStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGrid_GridStyle"]);
}
private void SetFileOneGridView(CloudItemViewingResponse item)
{
item.FspCiCheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCheck_StackLayoutStyle"]);
item.FspCiUncheck_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridUncheck_StackLayoutStyle"]);
item.FspCiMoreDetail_StackLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridMoreDetail_StackLayoutStyle"]);
item.FspCiCheckUncheck_ImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCheckUncheckMoreDetail_ImageStyle"]);
item.FspCiCheckUncheckMoreDetail_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCheckUncheckMoreDetail_WrapperLayoutStyle"]);
item.FspCiCloudItemInformation_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridCloudItemInformation_WrapperLayoutStyle"]);
item.FspCiThumbnailImage_WrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridThumbnailImage_WrapperLayoutStyle"]);
item.FspCiFolderThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridFolderThumbnailImageStyle"]);
item.FspCiFileThumbnailImageStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridFileThumbnailImageStyle"]);
item.FspCiThumbnailImageAndInformation_GeneralWrapperLayoutStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGridThumbnailImageAndInformation_GeneralWrapperLayoutStyle"]);
item.FspCi_GridStyle = (Style)((Application.Current.Resources.MergedDictionaries).ElementAt((int)EStyleItem.DevicesStyle)["FspCiOneGrid_GridStyle"]);
}
}
We would change the HasUnevenRows or CachingStrategy value for the listview in case of such broken. Does collectionview have something like this?
And collectionview grid doesn't broken on Android. But when I change grid, it turns back at the top of the list. If I swipe to bottom, I don't want to turn back to top when I change grid.
Thank you in advance.

Frame doesn't have shadow effect below Android Q

I've created a custom renderer for Frame to feel like CardView in Android it works fine on Android P but i've tested on API 21,22,23 it doesn't have any kind of effect. Here is my Android Renderer.
public class ShadowFrameRenderer : Xamarin.Forms.Platform.Android.AppCompat.FrameRenderer
{
public ShadowFrameRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
{
base.OnElementChanged(e);
if (e.NewElement != null && e.NewElement is ShadowFrame)
{
Elevation = 30.0f;
TranslationZ = 0.0f;
SetZ(30f);
//this.SetBackgroundResource(Resource.Drawable.shadow);
//GradientDrawable drawable = (GradientDrawable)this.Background;
//drawable.SetColor(Android.Graphics.Color.ParseColor("#F0F0F0"));
}
UpdateElevation();
}
private void UpdateElevation()
{
//var materialFrame = (ShadowFrame)Element;
// we need to reset the StateListAnimator to override the setting of Elevation on touch down and release.
if(Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
Control.StateListAnimator = new Android.Animation.StateListAnimator();
// set the elevation manually
ViewCompat.SetElevation(this, 10);
ViewCompat.SetElevation(Control, 10);
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
{
Control.Elevation = 10;
Control.CardElevation = 10;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
UpdateElevation();
//if (e.PropertyName == "Elevation")
//{
// UpdateElevation();
//}
}
}
Here is XAML.
<ContentPage.Content>
<controls:ShadowFrame Padding="10" Margin="10">
<Grid VerticalOptions="Start" HeightRequest="57" Margin="0,0,0,10" BackgroundColor="White">
<Grid ColumnSpacing="0" VerticalOptions="FillAndExpand">
<StackLayout BackgroundColor="{DynamicResource PMedium}"
x:Name="ListingLayoutB" VerticalOptions="FillAndExpand">
<Label Text="LISTING" HorizontalOptions="CenterAndExpand" TextColor="White" x:Name="ListingTxt"
FontSize="15" FontFamily="{StaticResource SBold}" VerticalOptions="CenterAndExpand"/>
</StackLayout>
<StackLayout Grid.Column="1" BackgroundColor="White" x:Name="DealsLayoutB" VerticalOptions="FillAndExpand">
<Label Text="DEALS" HorizontalOptions="CenterAndExpand" TextColor="{DynamicResource PMedium}" x:Name="DealsTxt"
FontSize="15" VerticalOptions="CenterAndExpand" FontFamily="{StaticResource SBold}"/>
</StackLayout>
</Grid>
</Grid>
</controls:ShadowFrame>
</ContentPage.Content>
And here is the result of above code. Screen shot taken from Android Emulator API level 23.
After setting BorderColor="White" the shadow is showing as expected.
Source: https://forums.xamarin.com/discussion/comment/416769#Comment_416769

Xamarin.forms - checkbox trigger another checkbox's CheckedChanged event

In my xamarin.forms app, I have a listview with checkboxes for the selection of the individual cell. What I am trying to do is multi select the checkboxes inside the listview by providing a "select all" checkbox outside the listview.The Multiselection works fine. For the "select all" checkbox click and individual checkbox click, I am performing some actions like an API Call. The Problem I am facing is Whenever I Click on the "select all" checkbox, the checkbox changed event of individual checkbox gets triggered.I know its natural But is there any way to prevent it like subscribe or unsubscribe the changed event of individual checkbox or something?
Xaml
<Grid >
<Grid.RowDefinitions>
<RowDefinitions Height="Auto"/>
<RowDefinitions Height="Auto"/>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" Orientation="Horizontal">
<Label Text="Select All" FontSize="Micro" TextColor="LawnGreen" HorizontalOptions="Start" VerticalOptions="Center" >
</Label>
<CheckBox x:Name="MultiselectCheckbox" ScaleX="0.8" ScaleY="0.8" CheckedChanged="MultiSelectCheckBox_CheckedChanged" IsChecked="False" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Color="LawnGreen"></CheckBox>
</StackLayout>
<ListView
x:Name="Listview"
HorizontalOptions="FillAndExpand"
ItemTapped="DistrictList_ItemTapped"
VerticalOptions="FillAndExpand" >
<ListView.ItemTemplate >
<DataTemplate >
<ViewCell >
<ViewCell.View>
<Frame HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding name}" FontSize="Micro" HorizontalOptions="StartAndExpand" VerticalOptions="Center" TextColor="Snow" Margin="5,0,0,0">
</Label>
<CheckBox CheckedChanged="Single_CheckedChanged" IsChecked="{Binding Selected}" Color="LightBlue" HorizontalOptions="End" >
</CheckBox>
</StackLayout>
</Frame>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Multiselect Checkbox checked event
private void MultiSelectCheckBox_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
if (!e.Value)
{
foreach (MyData TS in MyObject)
{
TS.Selected = false;
}
}
else{
foreach (MyData TS in MyObject)
{
TS.Selected = true;
}
PerformSomeAction();
}
}
Single selection Checkbox changed event
private void Single_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
if (!e.Value)
{
}
else{
PerformSomeAction();
}
}
Data Model
public class MyData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string name { get; set; }
private bool selected;
public bool Selected
{
get
{
return selected;
}
set
{
if (value != null)
{
selected = value;
NotifyPropertyChanged("Selected");
}
}
}
}
Agree with # Nikhileshwar , you could define some properties to get the different condition .And since you had used MVVM, you would better put all logic handling in your viewmodel .
in xaml
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" Orientation="Horizontal" HeightRequest="40" BackgroundColor="LightPink">
<Label Text="Select All" FontSize="Micro" TextColor="Red" HorizontalOptions="Start" VerticalOptions="Center" >
</Label>
<CheckBox x:Name="MultiselectCheckbox" ScaleX="0.8" ScaleY="0.8" IsChecked="{Binding MultiselectCheck}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Color="Red"></CheckBox>
</StackLayout>
<ListView Grid.Row="1"
x:Name="Listview"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding MyItems}"
VerticalOptions="FillAndExpand" >
<ListView.ItemTemplate >
<DataTemplate >
<ViewCell >
<Frame Padding="0" HeightRequest="40" HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding name}" FontSize="Micro" HorizontalOptions="StartAndExpand" VerticalOptions="Center" TextColor="Red" Margin="5,0,0,0">
</Label>
<CheckBox IsChecked="{Binding Selected}" Color="Red" HorizontalOptions="End" >
</CheckBox>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
in ViewModel
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
bool isMultiselect;
bool isSingleSelect;
public ObservableCollection<MyData> MyItems { get; set; }
private bool multiselectCheck;
public bool MultiselectCheck
{
get
{
return multiselectCheck;
}
set
{
if (multiselectCheck != value)
{
multiselectCheck = value;
if(!isSingleSelect)
{
isMultiselect = true;
foreach (MyData data in MyItems)
{
data.Selected = value;
}
isMultiselect = false;
}
NotifyPropertyChanged("MultiselectCheck");
}
}
}
public MyViewModel()
{
MyItems = new ObservableCollection<MyData>() {
new MyData(){name="Selection1" },
new MyData(){name="Selection2" },
new MyData(){name="Selection3" },
};
foreach(MyData data in MyItems)
{
data.PropertyChanged += Data_PropertyChanged;
}
}

Group Swtich Xamarin forms

I have a Listview that is creating dynamically data and a switch in every row, what i want is when i toggle a switch the others untoggle.
Is this possible to do?
Example:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Text="{Binding article_description}"
FontAttributes="Bold" FontSize="13" Margin="10,5,0,-6" Grid.Row="0" LineBreakMode="NoWrap"/>
<Label Text="{Binding dish_name}"
FontSize="13" Margin="10,0,0,2" Grid.Row="1" Grid.Column="0"/>
<Label Grid.Row="0" Grid.Column="0" x:Name="LabelReserved" Text="{Binding reserved}" IsVisible="false" LineBreakMode="NoWrap"/>
<Switch Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" HorizontalOptions="Start" VerticalOptions="Center" IsEnabled="False" Toggled="SwitchMenu_OnToggled" >
<Switch.Triggers>
<DataTrigger TargetType="Switch" Binding="{Binding Source={x:Reference LabelReserved},
Path=Text.Length}" Value="7">
<Setter Property="IsToggled" Value="true" />
</DataTrigger>
</Switch.Triggers>
</Switch>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
Note: This solution was a bit of an experiment on my part - so I would recommend that, if you decide to implement this, use it with caution.
The intent here is to extend Switch to be able to act as a grouped radio button.
First step would be to create a IsToggled or IsChecked or similar property in the item that acts as BindingContext to each list-item. You can implement an interface like:
public interface IToggableItem
{
string GroupName { get; } //not mandatory, only added to support grouped lists
bool IsChecked { get; set; }
}
Second step would be extend Switch to be aware of items-list. We can do that by adding a GroupContext bindable property - which basically represents the parent list-view's ItemsSource.
When a switch is toggled, it iterates through the items-list to set the property as false on other items.
For example:
public class GroupedSwitch : CustomSwitch
{
public static readonly BindableProperty IsGroupingEnabledProperty =
BindableProperty.Create(
"IsGroupingEnabled", typeof(bool), typeof(GroupedSwitch),
defaultValue: default(bool));
public bool IsGroupingEnabled
{
get { return (bool)GetValue(IsGroupingEnabledProperty); }
set { SetValue(IsGroupingEnabledProperty, value); }
}
public static readonly BindableProperty GroupContextProperty =
BindableProperty.Create(
"GroupContext", typeof(IEnumerable), typeof(GroupedSwitch),
defaultValue: default(IEnumerable));
public IEnumerable GroupContext
{
get { return (IEnumerable)GetValue(GroupContextProperty); }
set { SetValue(GroupContextProperty, value); }
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName != nameof(IsToggled))
return;
if (IsToggled != true || GroupContext == null)
return;
var currentItem = BindingContext as IToggableItem;
if (currentItem == null)
return;
if (IsGroupingEnabled)
{
var groupList = GroupContext as IEnumerable<IGrouping<string, IToggableItem>>;
var currentGroup = groupList.FirstOrDefault(x => x.Key == currentItem.GroupName);
if (currentGroup != null)
foreach (var item in currentGroup)
{
if (item != currentItem)
item.IsChecked = false;
}
}
else
{
var simpleList = GroupContext as IEnumerable<IToggableItem>;
if (simpleList != null)
foreach (var item in simpleList)
{
if (item != currentItem)
item.IsChecked = false;
}
}
}
}
Third step would be bind GroupContext property to parent ListView's items source. For example:
<ListView x:Name="ParentListView" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" VerticalOptions="Center">
<Label Text="{Binding Name}" />
<local:GroupedSwitch
IsToggled="{Binding IsChecked}"
GroupContext="{Binding ItemsSource, Source={x:Reference ParentListView}}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Or,
<ListView x:Name="_parentList" IsGroupingEnabled="true" >
<ListView.GroupHeaderTemplate>
<DataTemplate>
<TextCell Text="{Binding Key}" />
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" />
<local:GroupedSwitch
ToggledStateFromCode="{Binding IsSwitchOn}"
IsGroupingEnabled="true"
GroupContext="{Binding ItemsSource, Source={x:Reference _parentList}}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
EDIT 1: Updated code to add support for grouped list.
You should use triggers on each switch. Check this out:
https://www.tutorialspoint.com/xaml/xaml_triggers.htm

Resources