1
votes

I want to create a editable Spinner (or Picker in Xamarin.Forms). I have a custom renderer for my element (derived from Picker) that render the Picker as AutoCompleteTextView. Inside the renderer i have created AutoCompleteTextView that shows the dropdown menue if it on focus or is been clicked. Its worked fine.

My problem is that it shows like a EditText (or Entry in Xamarin.Forms) control on device, but i want to display it like a Spinner (or Picker on Xamarin.Forms).

Any idea how i have to make this?

EDIT: Here what i do in UWP: Custom Renderer for UWP control:

    CustomEditablePicker customControl; // Derived from Xamarin.Forms.Picker
    ComboBox nativeControl; // Windows.UI.Xaml.Controls.ComboBox 
    TextBox editControl;
    protected override void OnElementChanged(ElementChangedEventArgs<CustomEditablePicker> e)
    {
        base.OnElementChanged(e);

        customControl = e.NewElement;

        nativeControl = new ComboBox();

        editControl = new TextBox(); // First element of CheckBox would be a TextBox for edit some Text
        // Set the style (declarated in App.xaml)
        Style editableStyle = App.Current.Resources["ComboBoxItemTextBox"] as Style;

        if (editableStyle != null)
        {
            editControl.Style = editableStyle;

            ComboBoxItem item = new ComboBoxItem();
            item.IsSelected = true;         // Select First element
            item.Content = editControl;     // TextBox as content for first element

            nativeControl.Items.Add(item);
            nativeControl.SelectionChanged += NativeControl_SelectionChanged; // Do something if selection is changed

        }

        // Add items from custom element to native element
        foreach (var item in customControl.Items)
        {

            nativeControl.Items.Add(item);
        }

        editControl.KeyDown += EditControl_KeyDown; // Handle the space key
        editControl.TextChanged += EditControl_TextChanged; // Handle something if text inside TextBox is changed
        base.SetNativeControl(nativeControl); // Set native control to be displayed

    }


    /// <summary>
    /// Set text for Picker if value is changed 
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void EditControl_TextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox edit = (sender as TextBox);
        customControl.Text = edit.Text;
    }


    /// <summary>
    /// Handle Space-Key, without handle this key the ComboBox would be lost focus
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void EditControl_KeyDown(object sender, KeyRoutedEventArgs e)
    {
        if (e.Key == Windows.System.VirtualKey.Space)
        {
            if (editControl.SelectionLength > 0)
            {
                editControl.Text = editControl.Text.Remove(editControl.SelectionStart, editControl.SelectionLength);
                editControl.SelectionLength = 0;
            }
            int pos = editControl.SelectionStart;
            editControl.Text = editControl.Text.Insert(pos, " ");
            editControl.SelectionStart = pos + 1;
            e.Handled = true;
        }
    }


    /// <summary>
    /// Occurs when selection of the box is changed
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void NativeControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems.Count == 1 && e.AddedItems[0] != (sender as ComboBox).Items[0])
        {
            (sender as ComboBox).SelectedIndex = 0;
            editControl.Text = e.AddedItems[0] as String;

        }
    }

And The control in the PCL (Xamarin.Forms):

 public class CustomEditablePicker : Picker
{
    public static readonly BindableProperty EditTextProperty = BindableProperty.Create<CustomEditablePicker, string>(c => c.Text, String.Empty, BindingMode.TwoWay, propertyChanged: OnTextChanged);
    public event EventHandler<CustomUIEventArgs<string>> TextChanged;

    public static readonly BindableProperty Source = BindableProperty.Create<CustomEditablePicker, IEnumerable<string>>(l => l.ItemsSource, new List<string>(), BindingMode.TwoWay, propertyChanged: OnSourceChanged);

    private static void OnSourceChanged(BindableObject bindable, IEnumerable<string> oldValue, IEnumerable<string> newValue)
    {
        CustomEditablePicker customEditablePicker = (CustomEditablePicker)bindable;
        customEditablePicker.ItemsSource = newValue;
    }


    public event EventHandler<CustomUIEnumerableArgs<IEnumerable<string>>> SourceChanged;




    public IEnumerable<string> ItemsSource
    {
        get { return (List<string>)this.GetValue(Source); }

        set
        {
            if (this.ItemsSource != value)
            {
                this.SetValue(Source, value);
                if (SourceChanged != null)
                {
                    this.SourceChanged.Invoke(this, new CustomUIEnumerableArgs<IEnumerable<string>>(value));
                }
            }
        }
    }

    public string Text
    {
        get { return (string)this.GetValue(EditTextProperty); }
        set
        {
            if (this.Text != value)
            {
                this.SetValue(EditTextProperty, value);
                if (TextChanged != null)
                {
                    // Raise a event, with changed text
                    this.TextChanged.Invoke(this, new CustomUIEventArgs<string>(value));
                }
            }
        }
    }


    private static void OnTextChanged(BindableObject bindable, string oldValue, string newValue)
    {
        CustomEditablePicker customEditablePicker = (CustomEditablePicker)bindable;
        customEditablePicker.Text = newValue;
    }
}
1
What do you want to achieve? Little arrow at right side?Eugene
Yes, to recognize thet is not a EditText and have dropdown menueiwanlenin

1 Answers

1
votes

To show image inside EditText, use SetCompoundDrawablesWithIntrinsicBounds:

    protected override void OnElementChanged(ElementChangedEventArgs<SoundsPicker> e)
    {
        if (e.NewElement != null)
        {
            if (base.Control == null)
            {
                EditText editText = new EditText(Context)
                {
                    Focusable = false,
                    Clickable = true,
                    Tag = this
                };

                var padding = (int)Context.ToPixels(10);
                // that show image on right side
                editText.SetCompoundDrawablesWithIntrinsicBounds(0, 0, Resource.Drawable.arrow_down, 0);
                editText.CompoundDrawablePadding = padding;
                editText.SetOnClickListener(MyPickerPickerListener.Instance);
                editText.SetBackgroundDrawable(null);
                SetNativeControl(editText);
            }
        }
        base.OnElementChanged(e);
    }

Where is Resource.Drawable.arrow_down is your arrow image.

You can use tools like ILSpy or dotPeek to look at code inside Xamarin assembly.