问题
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.
回答1:
On iOS platform
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.
On Android platform
The underlying UI element for DatePicker on Android is EditText.
I have posted articles explaining how to manipulate context menu of EditText in native Android and Xamarin.Forms. 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) { }
}
=======
UPDATE: this question inspired me to create an article extending this answer with some explanations and details.
来源:https://stackoverflow.com/questions/52652007/i-need-to-block-the-paste-function-in-a-datepicker-on-xamarinforms