Xamarin.Forms(Nullable)DatePicker:缺少确定和取消事件的解决方法

时间:2017-07-31 15:33:03

标签: c# xamarin datepicker xamarin.forms nullable

我使用可以为空的DatePicker,它是通过DatePicker的子类化并使用自定义渲染器实现的。

public class ExtendedDatePicker : DatePicker
{
    public static readonly BindableProperty NullableDateProperty =
        BindableProperty.Create(
            "NullableDate", 
            typeof(DateTime?), 
            typeof(ExtendedDatePicker), 
            null, 
            BindingMode.TwoWay);

    public static readonly BindableProperty PlaceholderProperty =
        BindableProperty.Create(
            "Placeholder", 
            typeof(string), 
            typeof(ExtendedDatePicker), 
            string.Empty, 
            BindingMode.OneWay);

    public DateTime? NullableDate
    {
        get { return (DateTime?)GetValue(NullableDateProperty); }
        set
        {
            if (value != NullableDate)
            {
                SetValue(NullableDateProperty, value);
            }
        }
    }

    public string Placeholder
    {
        get { return (string)GetValue(PlaceholderProperty); }
        set { SetValue(PlaceholderProperty, value); }
    }

    public ExtendedDatePicker()
    {
        //this.Unfocused += ExtendedDatePicker_Unfocused;
        //this.DateSelected += ExtendedDatePicker_DateSelected;
    }

    //private void ExtendedDatePicker_DateSelected(object sender, DateChangedEventArgs e)
    //{
    //    NullableDate = Date;
    //}

    //private void ExtendedDatePicker_Unfocused(object sender, FocusEventArgs e)
    //{
    //    if (Device.RuntimePlatform == Device.Android && !e.IsFocused)
    //    {
    //        NullableDate = Date;
    //    }
    //}

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();
        UpdateDate();
    }

    protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == IsFocusedProperty.PropertyName)
        {
            if (IsFocused)
            {
                if (!NullableDate.HasValue)
                {
                    Date = (DateTime)DateProperty.DefaultValue;
                }
            }
            else
            {
                OnPropertyChanged(DateProperty.PropertyName);
            }
        }

        if (propertyName == DateProperty.PropertyName)
        {
            if (Date != default(DateTime))
            {
                if (Date != NullableDate.GetValueOrDefault())
                    NullableDate = Date;
            }
            else
            {
                if (NullableDate != null)
                    NullableDate = null;
            }
        }

        if (propertyName == NullableDateProperty.PropertyName)
        {
            if (NullableDate.HasValue)
            {
                if (Date != NullableDate.GetValueOrDefault())
                    Date = NullableDate.Value;
            }
        }
    }

    private void UpdateDate()
    {
        if (NullableDate.HasValue)
        {
            Date = NullableDate.Value;
        }
        else
        {
            Date = (DateTime)DateProperty.DefaultValue;
        }
    }
}

我不在这里提供自定义渲染器,因为它们大多数都是setter。我当前的方法有效,但必须通过一个额外的按钮清除所选日期,然后按"取消"仍然在datepicker中设置日期。现在我想改善这种行为,并且我正在寻找更好的解决方案。

的问题:

  • 用户应该能够从datepicker中选择任何日期(包括今天)
  • 能够清除当前所选日期
  • 取消应该像取消(并清除日期)
  • 适用于所有平台(iOS,Droid,UWP)

已经有feature request,但目前还没有实施。还有some tries来解决这个问题,但我还没有找到一个可行的解决方案,它解决了我的所有问题。

要么我可以使用DateSelected事件,如果我选择今天的日期(或最后选择的日期是准确的,并且在初始化时这是今天的日期),则不会被触发。或者我每次都设置NullableDate,在取消时也会显示日期。因此,如果用户按取消,则用户无法清除日期。我试图尝试Unfocused事件,但我还没有找到有用的东西。也许可以使用ViewRenderer并交换底层的原生视图来完全控制它?但是渲染器有wrong base classes ......

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。为此付出了很多努力。

无需监听DateSelected或Unfocused事件。

基本上,我们在ExtendedDatePicker中创建一个事件,然后在完成/取消单击可能的UpdateDate方法或根据您设置日期的流程时调用此事件。

现在在使用ExtendedDatePicker的视图中,.cs文件中的侦听OnDateSelected事件。

示例:

.xaml文件:

<xyz:BorderlessDatePicker x:Name="drawCalender" Format="dd-MMM-yyyy" />

.xaml.cs文件:

drawCalender.OnDateSelected += (object sender, DateChangedEventArgs e) =>
                {
                    ExtendedDatePicker calendarPicker = (ExtendedDatePicker)sender;
                    if (calendarPicker.NullableDate != null)
                    {
                        CalendarText = (DateTime)calendarPicker.NullableDate;
                    }
                    else
                    {
                        CalendarText = null;
                    }
                };

ExtendedDatePicker类:​​

public class ExtendedDatePicker : DatePicker
{
    public delegate void DateSelectedHandler(object sender, DateChangedEventArgs e);
    public event DateSelectedHandler OnDateSelected;

    public static readonly BindableProperty NullableDateProperty =
        BindableProperty.Create(
            "NullableDate", 
            typeof(DateTime?), 
            typeof(ExtendedDatePicker), 
            null, 
            BindingMode.TwoWay);


    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();
        UpdateDate();
    }

    protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == IsFocusedProperty.PropertyName)
        {
            if (IsFocused)
            {
                if (!NullableDate.HasValue)
                {
                    Date = (DateTime)DateProperty.DefaultValue;
                }
            }
            else
            {
                OnPropertyChanged(DateProperty.PropertyName);
            }
        }

        if (propertyName == DateProperty.PropertyName)
        {
            if (Date != default(DateTime))
            {
                if (Date != NullableDate.GetValueOrDefault())
                    NullableDate = Date;
            }
            else
            {
                if (NullableDate != null)
                    NullableDate = null;
            }
        }

        if (propertyName == NullableDateProperty.PropertyName)
        {
            if (NullableDate.HasValue)
            {
                if (Date != NullableDate.GetValueOrDefault())
                    Date = NullableDate.Value;
            }
        }
    }

    private void UpdateDate()
    {
        if (NullableDate.HasValue)
        {
            Date = NullableDate.Value;
        }
        else
        {
            Date = (DateTime)DateProperty.DefaultValue;
        }
        OnDateSelected(this, null);
    }
}

希望这会有所帮助。