locked
Picker: use different ItemDisplayBinding when collapsed<>expanded RRS feed

  • Question

  • User351103 posted

    Hi, What is the best way (possible at all?) to use different ItemDisplayBinding when picker is collapsed and expanded? E.g.: I have a list of object, which has ShortName and LongName properties. Like: {"EUR"/"Euro", "USD"/"USA Dollar", etc} When collapsed, the short name property should be used (to keep picker small on the GUI), but when you tap, use the long name property, to make selection easier. Picker has ItemDisplayBinding , but that is shared between collapsed<>expanded state. I was thinking to change ItemDisplayBinding when user opens/closes the Picker, but it has no such events to catch. Any idea? Thanks

    Wednesday, November 14, 2018 2:11 PM

Answers

  • User351103 posted

    Probably mixing JoeManke + ClintStLaurent idea might work:

    1 place transparent button on top of the picker 2 when clicked on the button, change the picker.ItemDisplayBinding to "Long" + call picker.Focus() to open list 3 in picker.Unfocused, set back picker.ItemDisplayBinding to "Short"

    The question, how can I implement point 1)? My picker is inside a Grid, which is inside a StackLayout, which is inside...

    <StackLayout Orientation="Vertical" Padding="10">
    ...
      <Grid>
          <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>
          <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>
    
      <Entry
          ...
          Grid.Row="0" Grid.Column="0"
        />
      <Picker 
          ...
          Grid.Row="0" Grid.Column="1"
        />
    </Grid>
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Thursday, November 15, 2018 9:31 AM

All replies

  • User180523 posted

    Maybe change the binding of ItemDisplayBinding when you expand/collapse the list? Toggle it between the Fullname and ShortName properties of your model?

    Wednesday, November 14, 2018 2:20 PM
  • User351103 posted

    Yes, but how to catch this moment: when you expand/collapse the list As I wrote, it has no such event, only Picker.SelectedIndexChanged Event

    Wednesday, November 14, 2018 2:33 PM
  • User180523 posted

    Then do something yourself to give you a trigger. ... Put a Button on top of the collapsed trigger. Set it to transparent. Nobody will see it. When someone clicks the button there's your trigger to swap binding, then open the Picker programmatically. Nobody will know the difference.

    Wednesday, November 14, 2018 2:52 PM
  • User351103 posted

    That sounds as a workable workaround, except a few issues:

    1) AFAIK there is no way(?) to open the Picker programmatically 2) if user closes the Picker without changing the selection (back button), then no way to catch this moment again, as Picker.SelectedIndexChanged Event is not called (I guess, have not tested), so cannot change it back to "shortname" property

    Wednesday, November 14, 2018 2:57 PM
  • User180523 posted

    Item 1 - Yep I know you can do it because I've done it. I don't recall of the top of my head how. Maybe I just set .Focus to the control and let it open itself. I don't remember now but I know I've done it. Item 2 - Then react to the back button.

    Honestly and please don't be mad when I say this - There will always be challenges in programming. Stop finding reasons why things can't be done and start looking at those same things as fun and interesting puzzles to work out. If it weren't for those challenges you'd be bored out of your mind grinding out grunt code.

    Wednesday, November 14, 2018 3:22 PM
  • User351103 posted

    I got what you are saying, but obviously I was looking for a "normal" way to do it, not a "too much hacky". It might be challenging to spend hours/days on something, but if you are (as usually you are) short of time, you don't like this. Best xamarin solution would be to split ItemDisplayBinding => ItemDisplayBindingCollapsed/ItemDisplayBindingExpanded. This case, the workaround* looks too much, so most probably going to look for other way. I prefer to keep my code clean than have the best possible GUI...

    Anyway, thanks your help, I guess if you also don't know easier way, the probably does not exist...

    *position and resize the transparent button to the given position *figure our how to programmatically open the picker *handle the back button on Android (maybe also clicking outside of the picker?) *handle the cancel(?) button on IOS (that has no back button, so ???) *other unforeseen problems/challenges

    Wednesday, November 14, 2018 3:33 PM
  • User53115 posted

    Couldn't you use the Focused/Unfocused events of the Picker?

    Wednesday, November 14, 2018 3:43 PM
  • User180523 posted

    @Zoli said: I got what you are saying, but obviously I was looking for a "normal" way to do it, not a "too much hacky".

    In Xamarin they are sometimes one and the same. {laugh} Normal is vague. Normal for me is not normal for you. Everyone has a different approach based on their experience, style and preferences. Like you said, there are no obvious events on the Picker you can tie in to so you have to make up some type of work around.

    Or... Maybe you can take a different approach. If you're doing all this because you want to keep the collapsed display narrow, then maybe just string.format the displayed text to the first 5 characters and you don't have to worry about all the events and changing things.

    What you can do and what you need to do and what you're limited to is based on the business rules for the app you're making. Maybe its okay to truncate to 5 chars; maybe its not what your bosses will accept. Maybe you don't display anything on the collapsed Picker and instead put a Label on top of it for the short display text.

    *position and resize the transparent button to the given position *figure our how to programmatically open the picker *handle the back button on Android (maybe also clicking outside of the picker?) *handle the cancel(?) button on IOS (that has no back button, so ???) *other unforeseen problems/challenges

    That pretty much is the day-to-day job description. Coding in a perfect world, with no errors, no problems, and with an eco-system that has no shortcomings would be ideal and would also make it so mundane that anyone could do it at $20/hr. The nature of the real world of development where you have to work around issues, code robustly, account for errors or failed connections and failed hardware, and the unexpected is what filters out those that shouldn't be doing this for a living as well as keeps us earning a wage higher than a barista. Its what divides the keyboard bangers from the software-engineers.

    Wednesday, November 14, 2018 3:53 PM
  • User180523 posted

    @JoeManke said: Couldn't you use the Focused/Unfocused events of the Picker?

    I suggested that. He didn't like the 'hacky' nature of it.

    Wednesday, November 14, 2018 3:54 PM
  • User351103 posted

    Couldn't you use the Focused/Unfocused events of the Picker?

    _picker.Focused += (s, e) =>
    {
        _picker.ItemDisplayBinding = new Binding("Long");  //show long name when expanded
    };
    _picker.Unfocused += (s, e) =>
    {
        _picker.ItemDisplayBinding = new Binding("Short"); //show short name when collapsed
    };
    

    What happens, form opens, picker collapsed, shows the "Short" property of the selected item. This is ok.
    Tap on it, _picker.Focused is called, binding is changed to "Long", HOWEVER the expanded list still shows the "Short" property. You select something, picker collapses, and displays the selected item's "Long" for a moment, then changes to "Short", also sets the SelectedIndex = -1, but that's not an issue right now, just save and restore before/after change binding.

    So it seems, Focused is called after the expanded list is already populated, so changing the binding here only affects after the picker is collapsed.

    (tested only on Android, iOS might have other surprises)

    Thursday, November 15, 2018 9:17 AM
  • User351103 posted

    Probably mixing JoeManke + ClintStLaurent idea might work:

    1 place transparent button on top of the picker 2 when clicked on the button, change the picker.ItemDisplayBinding to "Long" + call picker.Focus() to open list 3 in picker.Unfocused, set back picker.ItemDisplayBinding to "Short"

    The question, how can I implement point 1)? My picker is inside a Grid, which is inside a StackLayout, which is inside...

    <StackLayout Orientation="Vertical" Padding="10">
    ...
      <Grid>
          <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>
          <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>
    
      <Entry
          ...
          Grid.Row="0" Grid.Column="0"
        />
      <Picker 
          ...
          Grid.Row="0" Grid.Column="1"
        />
    </Grid>
    
    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Thursday, November 15, 2018 9:31 AM
  • User180523 posted

    Set the button to the same row and column as the picker. <Picker Row="0" Column = "0" <Button Row ="0" Column = "0" Button will be on top of PIcker

    Thursday, November 15, 2018 12:51 PM
  • User351103 posted

    Tried, indeed it (more or less) works:

    1. Create a picker
    2. Put a (transparent) button on top of it to cover
    3. Handle button.Click() = {picker.ItemDisplayBinding= "long" ; picker.Focus(); }
    4. Handle picker.Unfocused() = {picker.ItemDisplayBinding = "SHORT";}

    Note: changing 'ItemDisplayBinding' will invalidate the current selection, so you have to save+restore before/after changing the binding. Also, cancel has to be handled, this case new selectedIndex=-1.

    Some GUI flicker you will see (when changing the binding) but more or less it does what we need. Thanks the tips.

    Something like

    {
      _picker.Unfocused += ClosePicker;
      _button.Clicked += OpenPicker;
    }
    
    int _savedSelectedIndex;
    private void ClosePicker(object sender, FocusEventArgs e)
    {
      int index = picker.SelectedIndex == -1 /*cancel*/ ? _savedSelectedIndex : _picker.SelectedIndex;
      _picker.ItemDisplayBinding = new Binding("SHORT");
      _picker.SelectedIndex = index;
    }
    
    private void OpenPicker(object sender, EventArgs e)
    {
      _savedSelectedIndex = _picker.SelectedIndex;
      _picker.ItemDisplayBinding = new Binding("LONG");
      _picker.Focus();
    }
    
    Monday, November 19, 2018 3:40 PM
  • User351103 posted

    Update, after tested in iOS, you need additional modifications:

    private void OpenPicker(object sender, EventArgs e)
    {
      _savedSelectedIndex = _picker.SelectedIndex;
      _picker.ItemDisplayBinding = new Binding("LONG");
      _picker.SelectedIndex = _savedSelectedIndex;  <<=========== this needed for iOS, as its picker (unlike Android) shows the selection
      _picker.Focus();
    }
    
    Tuesday, November 20, 2018 9:32 AM