0
votes

I have used Switch to toggle data, if I add an event it work's fine. I'm trying to remove handler on data binding so that the event handler stay put. But I'm not getting the element by it's name.

<ListView Grid.Column="2" x:Name="DynamicListView" IsPullToRefreshEnabled="False" ItemSelected="DynamicListViewItemSelected" IsVisible="false" WidthRequest="380" RowHeight="75">
<ListView.ItemTemplate>
     <DataTemplate>
          <ViewCell>
               <StackLayout Orientation ="Horizontal" >
                   <Label x:Name="configLabel" Text="{Binding Name}" HorizontalOptions="StartAndExpand" Style="{StaticResource BigBlackLabelLeft}"  />
                   <Switch x:Name="configSwitch" HorizontalOptions="End" OnColor="LightSeaGreen" IsToggled="{Binding IsVisible}" Toggled="HandleSwitchToggledByUser" />
               </StackLayout>
           </ViewCell>
      </DataTemplate>
</ListView.ItemTemplate>
</ListView>

So on the code behind I'm trying to access Label/Switch by configLabel/configSwitch but i'm getting error saying The name configSwitch does not exist on the current context. I'm not sure what's going wrong here.

2
you can't access items in templates from the code behind by name because there may be 0 or 1000 copies of that template created at run time. If you would explain exactly what you're trying to do we could suggest an alternative approach. - Jason
I'm trying to use switch as user settings, for example turn on/off wifi. Here I'm using Label as placeholder for text and Switch to toggle. My idea was to capture the binding object on the event to get what exact value user wants to modify. - 3not3
try CommandParameter="{Binding .}", then you can get that value from the sender in your event handler - Jason
I don't think command is available in Switch, I'm looking this https://stackguides.com/questions/41070613/xamarin-forms-switch-toggled-event-doesnt-bind-with-viewmodel post - 3not3
use can just use the BindingContext of sender instead - Jason

2 Answers

1
votes

If there are only two subviews in the ViewCell, I would access the control in this way:

First, I created a custom mySwitch and add a bindable property name to it, you can use this name later to figure out which switch you are toggling:

    public class mySwitch : Switch
    {

        public static readonly BindableProperty nameProperty =
  BindableProperty.Create("name", typeof(string), typeof(MainPage), null);

        public string name
        {
            get { return (string)GetValue(nameProperty); }
            set { SetValue(nameProperty, value); }
        }
    }

In xaml, here I write a listView as an example and I set binding to the name of switch as the same as text of label:

<ContentPage.Content>

    <ListView>
        <ListView.ItemsSource>
            <x:Array Type="{x:Type x:String}">
                <x:String>wifi</x:String>
                <x:String>sound</x:String>
            </x:Array>
        </ListView.ItemsSource>

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout BackgroundColor="#eee" Orientation="Vertical">
                        <StackLayout Orientation="Horizontal">
                            <Label Text="{Binding .}" TextColor="#f35e20" />
                            <local:mySwitch name="{Binding .}"  HorizontalOptions="End" OnColor="LightSeaGreen" IsToggled="{Binding IsVisible}" Toggled="Switch_Toggled" />
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

</ContentPage.Content>

in code behind, you can access the switch by sender, access the ParentStackLayout by sender.parent, and access the label by (Label)ParentStackLayout.Children[0], then use the name of switch to distinguish switch and change the text of corresponding configLabel:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void Switch_Toggled(object sender, ToggledEventArgs e)
    {
        // access switch
        var Switch_ToggledHandler = (mySwitch)sender;

        // access Parent Layout for Sender  
        StackLayout ParentStackLayout = (StackLayout)Switch_ToggledHandler.Parent;

        // access the Label "configLabel"  
        Label configLabel = (Label)ParentStackLayout.Children[0];


        if (Switch_ToggledHandler.IsToggled)
        {
            switch (Switch_ToggledHandler.name)
            {
                case "wifi":
                    configLabel.Text = "wifi open";
                    break;
                case "sound":
                    configLabel.Text = "sound is open";
                    break;
                default:
                    Console.WriteLine("Default case");
                    break;
            }

        }
        else {

            switch (Switch_ToggledHandler.name)
            {
                case "wifi":
                    configLabel.Text = "wifi off";
                    break;
                case "sound":
                    configLabel.Text = "sound is off";
                    break;
                default:
                    Console.WriteLine("Default case");
                    break;
            }
        }
    }
}

Here is a gif:

gif

I also upload my demo here and you can check it. Let me know if it works for you.

0
votes

If you want to grab the BindingContext of your ViewCell in the toggled event, that's very simple: simply cast the sender parameter to a View and its BindingContext to the class of the items shown in the list, then read from it the value that you need:

    private void HandleSwitchToggledByUser(object sender, ToggledEventArgs e)
    {
        if (sender is View v && v.BindingContext is ItemClass item)
        {
            var switchName = item.Name;
        }
    }