10
votes

Xamarin.Forms on Android. Clicking picker opens dialog and the negative button has default text of "Cancel". How can I change it?

I looked in open source project of Xamarin and they set the positive button text like this

builder.SetNegativeButton(global::Android.Resource.String.Cancel, (s, a) => ...

This method is private so I cant override the class method.

Neither I can copy paste implementation of this class because its members are private to Xamarn dll-s...

Link to that picker implementation on Xamarin.Forms andoid:

https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Platform.Android/Renderers/PickerRenderer.cs

2
submit a pull requestJason
And replace the code? and include it in my project instead of xamarin nuget package?mister_giga
Could you just use your own renderer? Just almost copypaste the implementation from Xamarin and extend it to have a way to change the text.tjugg
just for changing a string value is never a good idea to reinvent whole bicyclemister_giga
Well, it's pretty obvious you have two options, either do a PR and wait for it to be accepted to the official repository or then you do your own implementation and use it?tjugg

2 Answers

6
votes

Xamarin forms Picker on android change Cancel text

As an alternative choice, you could rewrite the whole dialog in your PickerRenderer :

public class MyPickerRenderer : Xamarin.Forms.Platform.Android.PickerRenderer
{
    private IElementController ElementController => Element as IElementController;
    private AlertDialog _dialog;

    protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement == null || e.OldElement != null)
            return;

        Control.Click += Control_Click;
    }

    protected override void Dispose(bool disposing)
    {
        Control.Click -= Control_Click;
        base.Dispose(disposing);
    }

    private void Control_Click(object sender, EventArgs e)
    {
        Picker model = Element;

        var picker = new NumberPicker(Context);
        if (model.Items != null && model.Items.Any())
        {
            picker.MaxValue = model.Items.Count - 1;
            picker.MinValue = 0;
            picker.SetDisplayedValues(model.Items.ToArray());
            picker.WrapSelectorWheel = false;
            picker.DescendantFocusability = DescendantFocusability.BlockDescendants;
            picker.Value = model.SelectedIndex;
        }

        var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
        layout.AddView(picker);

        ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);

        var builder = new AlertDialog.Builder(Context);
        builder.SetView(layout);
        builder.SetTitle(model.Title ?? "");
        builder.SetNegativeButton("Cancel =-= ", (s, a) =>
        {
            ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
            // It is possible for the Content of the Page to be changed when Focus is changed.
            // In this case, we'll lose our Control.
            Control?.ClearFocus();
            _dialog = null;
        });
        builder.SetPositiveButton("Ok 0.0", (s, a) =>
        {
            ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
            // It is possible for the Content of the Page to be changed on SelectedIndexChanged.
            // In this case, the Element & Control will no longer exist.
            if (Element != null)
            {
                if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
                    Control.Text = model.Items[Element.SelectedIndex];
                ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
                // It is also possible for the Content of the Page to be changed when Focus is changed.
                // In this case, we'll lose our Control.
                Control?.ClearFocus();
            }
            _dialog = null;
        });

        _dialog = builder.Create();
        _dialog.DismissEvent += (ssender, args) =>
        {
            ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
        };
        _dialog.Show();
    }
}

Effect.

0
votes

As the dialog itself is not a graphical element that is directly used in XAML, there is nothing that stops you from using the Android code directly in your project. If you use the shared project it is as simple as using the conditional compiling, if you use standard library then you need to use the dependency service.

On the XAML side you can use a sort of custom EntryRenderer to present the picked item on the screen, that is what Xamarin does with that anyway.