• 1
Votes
name

Update: Just a reminder, there's a 500 point bonus on this if someone can just show me how to implement this functionality without using Gestures>

I am using a ViewCell and a gesture recognizer to open up a picker with the following code. The ViewCell has a label on the left and a label area on the right that is populated initially when the app starts and later with the picker when the ViewCell is clicked.

XAML

<ViewCell x:Name="ati" Tapped="OpenPickerCommand">
   <Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
      <Grid.GestureRecognizers>
         <TapGestureRecognizer 
             Command="{Binding OpenPickerCommand}" 
             CommandParameter="{x:Reference atiPicker}" NumberOfTapsRequired="1" />
      </Grid.GestureRecognizers>
      <local:LabelBodyRendererClass Text="Answer Time Interval" HorizontalOptions="StartAndExpand" />
      <Picker x:Name="atiPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="atiPickerSelectedIndexChanged" ItemsSource="{Binding Times}"></Picker>
      <local:LabelBodyRendererClass x:Name="atiLabel" HorizontalOptions="End"/>
   </Grid>
</ViewCell>

<ViewCell x:Name="pti" Tapped="OpenPickerCommand">
   <Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
      <Grid.GestureRecognizers>
         <TapGestureRecognizer 
             Command="{Binding OpenPickerCommand}" 
             CommandParameter="{x:Reference ptiPicker}" NumberOfTapsRequired="1" />
      </Grid.GestureRecognizers>
      <local:LabelBodyRendererClass Text="Phrase Time Interval" HorizontalOptions="StartAndExpand" />
      <Picker x:Name="ptiPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="ptiPickerSelectedIndexChanged" ItemsSource="{Binding Times}"></Picker>
      <local:LabelBodyRendererClass x:Name="ptiLabel" HorizontalOptions="End"/>
   </Grid>
</ViewCell>

C# This works for different pickers (ati, bti, pti etc) with CommandParameter

public SettingsPage()
{
   InitializeComponent();
   BindingContext = new CommandViewModel();
}

void atiPickerSelectedIndexChanged(object sender, EventArgs e)
    {
        var picker = (Picker)sender;
        int selectedIndex = picker.SelectedIndex;
        if (selectedIndex != -1)
        {
            App.DB.UpdateIntSetting(Settings.Ati, selectedIndex);
            atiLabel.Text = AS.ati.Text();
        }
    }

void ptiPickerSelectedIndexChanged(object sender, EventArgs e)
    {
        var picker = (Picker)sender;
        int selectedIndex = picker.SelectedIndex;
        if (selectedIndex != -1)
        {
            App.DB.UpdateIntSetting(Settings.Pti, selectedIndex);
            ptiLabel.Text = AS.pti.Text();
        }
    }


public class CommandViewModel: ObservableProperty
{
    public ICommand openPickerCommand;

    public CommandViewModel()
    {
        openPickerCommand = new Command<Picker>(PickerFocus);
        //openPickerCommand = new Command(tapped);
    }

    public ICommand OpenPickerCommand
    {
        get { return openPickerCommand; }
    }

    void PickerFocus(Picker param)
    {
        param.Focus();
    }
}

I would like to remove the use of TapGestureRecognizers but I still want to retain the functionality and layout.

It's been suggested to me that it would be better if I used the Tapped event of the ViewCell like this:

 Tapped="OnTapped"

Can someone explain in some detail how I could wire this up in C#. Would I be best to code something into the CommandViewModel as well as in the C# backing code. Also can the view model have one method that takes an argument so it could be used to open up different pickers?

An example of how I could do this would be very much appreciated. Note that I don't particularly need to use the CommandViewModel if there is a way that I could do this by coding just in the .cs backing code.

 

(Sorry for the poor english)

Despite not being best practice, I guess you can do something like this, dismissing the viewmodel:

XAML:

<ViewCell x:Name="ati" Tapped="OpenPickerCommand">
   <Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
      <local:LabelBodyRendererClass Text="Answer Time Interval" HorizontalOptions="StartAndExpand" />
      <Picker x:Name="atiPicker" 
              IsVisible="false" 
              HorizontalOptions="End" 
              SelectedIndexChanged="atiPickerSelectedIndexChanged" 
              ItemsSource="{Binding Times}">
      </Picker>
      <local:LabelBodyRendererClass x:Name="atiLabel" HorizontalOptions="End"/>
   </Grid>
</ViewCell>

<ViewCell x:Name="pti" Tapped="OpenPickerCommand">
   <Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
      <local:LabelBodyRendererClass Text="Phrase Time Interval" HorizontalOptions="StartAndExpand" />
      <Picker x:Name="ptiPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="ptiPickerSelectedIndexChanged" ItemsSource="{Binding Times}"></Picker>
      <local:LabelBodyRendererClass x:Name="ptiLabel" HorizontalOptions="End"/>
   </Grid>
</ViewCell>

C#:

private void OpenPickerCommand(object sender, System.EventArgs e)
{
    if (sender != null)
    {
        Picker pkr = sender == ati ? atiPicker : ptiPicker;
        pkr.Focus();
    }
}

Answering your question "Can the view model have one method that takes an argument?", it is exactly what you're already doing using the 'OpenPickerCommand' method. The problem is that using the ViewCell's public event 'Tapped', you can't set parameters to the delegate handler.

Let me know if it works for you or if you do need some more information.

I hope it helps.

  • 0
Reply Report