如何创建可编辑微调器(选择器)?

How to create a Editable Spinner (Picker)?

我想创建一个可编辑的 Spinner(或 Xamarin.Forms 中的 Picker)。 我的元素(派生自 Picker)有一个自定义渲染器,它将 Picker 渲染为 AutoCompleteTextView。在渲染器中,我创建了 AutoCompleteTextView,如果它处于焦点或被单击,它会显示下拉菜单。它工作正常。

我的问题是它在设备上显示为 EditText(或 Xamarin.Forms 中的条目)控件,但我想将其显示为微调器(或 Xamarin.Forms 中的选择器)。

知道我该怎么做吗?

编辑: 这是我在 UWP 中所做的: UWP 控件的自定义渲染器:

    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;

        }
    }

和 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;
    }
}

要在 EditText 中显示图像,请使用 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);
    }

Resource.Drawable.arrow_down 哪里是你的箭头图像。

您可以使用 ILSpy 或 dotPeek 等工具查看 Xamarin 程序集中的代码。