
Question:
In the solution that I'm building, I have a date-picker that works fine. But, if the user press the touch and paste something, it will overwrite the date.
When the user pastes, the events of OnElementChanged
, OnElementPropertyChanged
and even the INotifyPropertyChanged
are not raised. I also can't find a option to block the paste function. (When the date is choose normally, the events are being called.)
This happens in iOS and Android. Can someone help me? I am stuck and my researches don't help me much.
Answer1:<strong>On iOS platform</strong>
DatePicker
behaves this way because under the hood it is implemented via UITextField
.
To avoid editing of UITextField
you have to assign it a delegate which returns false
from ShouldChangeCharacters
method.
The full solution will be the following:
Declare a child of a DatePicker
in a shared project:
public class ExtendedDatePicker : DatePicker
{
}
Declare a corresponding renderer in iOS project:
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
...
public class ExtendedDatePickerRenderer : DatePickerRenderer
{
private UneditableUITextFieldDelegate _delegate = new UneditableUITextFieldDelegate();
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
Control.Delegate = _delegate;
}
}
Implement the UneditableUITextFieldDelegate
:
public class UneditableUITextFieldDelegate : NSObject, IUITextFieldDelegate
{
[Export("textField:shouldChangeCharactersInRange:replacementString:")]
public bool ShouldChangeCharacters(UITextField textField, NSRange range, string replacementString) =>
false;
}
This will not prevent the 'copy'/'paste' menu from being shown but DatePicker
value will not be changed after pressing them.
<strong>On Android platform</strong>
The underlying UI element for DatePicker
on Android is EditText
.
I have posted articles explaining how to manipulate context menu of EditText
in <a href="https://medium.com/@anna.domashych/selectable-read-only-multiline-text-field-on-android-169c27c55408" rel="nofollow">native Android</a> and <a href="https://medium.com/@anna.domashych/selectable-read-only-multiline-text-field-in-xamarin-forms-69d09276d580" rel="nofollow">Xamarin.Forms</a>. You can get the overall idea there.
I was not able to perform a long tap on a DatePicker
to see the problem thus I can only guess about the proper fix, but a renderer similar to this one should completely disable context menu for selected text as well as a paste option when a user taps a cursor:
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
...
public class ExtendedDatePickerRenderer : DatePickerRenderer
{
public ExtendedDatePickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
Control.CustomSelectionActionModeCallback = new CustomSelectionActionModeCallback();
Control.CustomInsertionActionModeCallback = new CustomInsertionActionModeCallback();
}
}
CustomInsertionActionModeCallback
and CustomInsertionActionModeCallback
would return false
from OnCreateActionMode
and will prevent menu from appearing.
public class CustomInsertionActionModeCallback : Java.Lang.Object, ActionMode.ICallback
{
public bool OnCreateActionMode(ActionMode mode, IMenu menu) => false;
public bool OnActionItemClicked(ActionMode m, IMenuItem i) => false;
public bool OnPrepareActionMode(ActionMode mode, IMenu menu) => true;
public void OnDestroyActionMode(ActionMode mode) { }
}
public class CustomSelectionActionModeCallback : Java.Lang.Object, ActionMode.ICallback
{
public bool OnActionItemClicked(ActionMode m, IMenuItem i) => false;
public bool OnCreateActionMode(ActionMode mode, IMenu menu) => false;
public bool OnPrepareActionMode(ActionMode mode, IMenu menu) => true;
public void OnDestroyActionMode(ActionMode mode) { }
}
<strong>=======</strong><br /><strong>UPDATE:</strong> this question inspired me to create an <a href="https://medium.com/@anna.domashych/xamarin-forms-disabling-cut-paste-menu-on-datepicker-e2dc96298a8f" rel="nofollow">article</a> extending this answer with some explanations and details.