Reputation: 427
<StackLayout BackgroundColor="White">
<ListView x:Name="ListViewMenu" ItemsSource="{Binding Menus}"
HasUnevenRows="True"
BackgroundColor="White"
SeparatorVisibility="None"
VerticalOptions="FillAndExpand"
ItemTapped="Handle_ItemTapped"
ItemSelected="Handle_ItemSelected"
IsGroupingEnabled = "true"
SeparatorColor="White">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout BackgroundColor="LightSkyBlue" HeightRequest="25">
<Label Text="{Binding Key}" FontAttributes="Bold" LineBreakMode="NoWrap" Margin="10,0,0,0">
</Label>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<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>
</ListView>
</StackLayout>
I have the listview above, that has a switch, I have a trigger to toggle the switch if the labelreserved has a legth of 7, but I dont want the Toggled event to fire, only when the user clicks on the switch. Is possible to do what I want?
Upvotes: 1
Views: 1564
Reputation: 176
This question is old, but I found a simple (somewhat incorrect) solution that I used to save a lot of extra work from the accepted answer. When I programmatically toggle the switch, I set the Tag property to true.
ToggleSwitch.Tag = true;
ToggleSwitch.IsOn = true (or false);
Then in my Toggled event I check if the Tag property is null and perform my action. That way the only time the code is executed is when the user toggles the switch.
private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
ToggleSwitch toggleSwitch = (ToggleSwitch)e.OriginalSource;
if (toggleSwitch.Tag == null)
{
// Switch was toggled by user, do some action.
}
else
{
// Switch was toggled programmatically, set Tag null.
toggleSwitch.Tag = null;
}
}
Upvotes: 0
Reputation: 13591
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.
Basically, the intent is to create a view-only solution that is able to track how the IsToggled
property is being set - whether it is through trigger, binding context or, tap action (something similar to property context that is maintained for BindingContext
on BindableObject
)
Assuming, we have a custom-event that is triggered only when user taps the switch - this problem should be solved. Simply adding a tap-recognizer to Switch
didn't seem to work. And we are left with 2 options:
Create your own custom control that provides functionality similar to Switch
, but only triggers the toggle event when there is a tap gesture captured - would highly recommend this option.
Or, you can extend existing Switch
control with a custom event, and tracks how the IsToggled
property is set - by providing its own set of bindable properties.
For example:
public class CustomSwitch : Switch
{
internal enum ToggledSetFlags
{
None = 0,
FromCode = 1 << 0,
}
ToggledSetFlags _toggleSetStatus = ToggledSetFlags.None;
public event EventHandler<ToggledEventArgs> UserToggled;
public static readonly BindableProperty ToggledStateFromCodeProperty =
BindableProperty.Create(
"ToggledStateFromCode", typeof(bool), typeof(CustomSwitch),
defaultBindingMode: BindingMode.TwoWay,
defaultValue: default(bool), propertyChanged: OnToggledStateFromCodeChanged);
public bool ToggledStateFromCode
{
get { return (bool)GetValue(ToggledStateFromCodeProperty); }
set { SetValue(ToggledStateFromCodeProperty, value); }
}
private static void OnToggledStateFromCodeChanged(BindableObject bindable, object oldValue, object newValue)
{
((CustomSwitch)bindable).OnToggledStateFromCodeChangedImpl((bool)oldValue, (bool)newValue);
}
protected virtual void OnToggledStateFromCodeChangedImpl(bool oldValue, bool newValue)
{
if (ToggledStateFromCode != IsToggled)
{
_toggleSetStatus = ToggledSetFlags.FromCode;
IsToggled = ToggledStateFromCode;
}
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(IsToggled))
{
ToggledStateFromCode = IsToggled;
if (_toggleSetStatus == ToggledSetFlags.None)
UserToggled?.Invoke(this, new ToggledEventArgs(IsToggled));
else
_toggleSetStatus = ToggledSetFlags.None;
}
}
}
And, sample usage would look like:
<local:CustomSwitch
Grid.Row="0" Grid.RowSpan="2" Grid.Column="1"
HorizontalOptions="Start" VerticalOptions="Center"
ToggledStateFromCode="{Binding IsSwitchOn}"
UserToggled="SwitchMenu_OnToggled">
<Switch.Triggers>
<DataTrigger TargetType="{x:Type local:CustomSwitch}"
Binding="{Binding Source={x:Reference LabelReserved},
Path=Text.Length}" Value="7">
<Setter Property="ToggledStateFromCode" Value="true" />
</DataTrigger>
</Switch.Triggers>
</local:CustomSwitch>
EDIT 1: Had missed to add else
in OnPropertyChanged
method while reverting custom toggled property status. Also, added check to set flag only if current toggle value is different.
EDIT 2: Converted bindable property to track state instead of state-less as before. This ensures the ability to handle binding changes without firing the event.
Upvotes: 3
Reputation: 2617
You can prevent the user from toggling the switch by disabling the Switch by using the property IsEnabled
and set it to false .
Upvotes: 0