【问题标题】:Xamarin forms DateTime PickerXamarin 形成日期时间选择器
【发布时间】:2020-03-16 01:51:27
【问题描述】:

我在网上找到了一个自定义渲染器,但是有一个错误。有谁知道如何进行日期时间控制?目前我正在使用单独的日期选择器和时间选择器,但我希望将它结合起来。

我将在下面发布我从另一篇文章中找到的代码。这是帖子Xamarin Forms date and time picker的链接

using System;

using Foundation;
using Test;
using Test.Droid;
using UIKit;
using ObjCRuntime;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly:ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace Test.Droid
{
public class MyPickerRenderer : PickerRenderer
{

    string SelectedValue;

    [Obsolete]
    public MyPickerRenderer()
    {

    }

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

        if (Control != null)
        {
            SetTimePicker();
        }

    }


    void SetTimePicker()
    {
        UIDatePicker picker = new UIDatePicker
        {
            Mode = UIDatePickerMode.DateAndTime
        };

        picker.SetDate(NSDate.Now, true);

        picker.AddTarget(this, new Selector("DateChange:"), UIControlEvent.ValueChanged);

        Control.InputView = picker;


        UIToolbar toolbar = (UIToolbar)Control.InputAccessoryView;

        UIBarButtonItem done = new UIBarButtonItem("Done", UIBarButtonItemStyle.Done, (object sender, EventArgs click) =>
        {
            Control.Text = SelectedValue;
            toolbar.RemoveFromSuperview();
            picker.RemoveFromSuperview();
            Control.ResignFirstResponder();
            MessagingCenter.Send<Object, string>(this, "pickerSelected", SelectedValue);



        });

        UIBarButtonItem empty = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace, null);

        toolbar.Items = new UIBarButtonItem[] { empty, done };

    }

    [Export("DateChange:")]
    void DateChange(UIDatePicker picker)
    {
        NSDateFormatter formatter = new NSDateFormatter();

        formatter.DateFormat = "MM-dd HH:mm aa"; //you can set the format as you want

        Control.Text = formatter.ToString(picker.Date);

        SelectedValue = formatter.ToString(picker.Date);

        MessagingCenter.Send<Object, string>(this, "pickerSelected", SelectedValue);
      }
   }
}

【问题讨论】:

  • “有一个错误” - 如果您告诉我们具体的错误是什么,将会非常有帮助。
  • 我在 android 而不是 IOS 上使用,所以我不确定这是否会导致错误。我得到的错误是“严重性代码描述项目文件行抑制状态错误 CS1061 'EditText' 不包含'ResignFirstResponder' 的定义并且没有可访问的扩展方法'ResignFirstResponder' 接受'EditText' 类型的第一个参数可以找到(是您缺少 using 指令或程序集引用?)"

标签: xaml xamarin xamarin.forms


【解决方案1】:

让 DateTimePicker 继承 ContentView 而不仅仅是一个 Entry,然后创建 Stacklayout,将 Entry 以及日期和时间选择器添加到内容中。

查看 DateTimePicker2.cs:

  public class DateTimePicker2 : ContentView, INotifyPropertyChanged
{
    public Entry _entry { get; private set; } = new Entry();
    public DatePicker _datePicker { get; private set; } = new DatePicker() { MinimumDate = DateTime.Today, IsVisible = false };
    public TimePicker _timePicker { get; private set; } = new TimePicker() { IsVisible = false };
    string _stringFormat { get; set; }
    public string StringFormat { get { return _stringFormat ?? "dd/MM/yyyy HH:mm"; } set { _stringFormat = value; } }
    public DateTime DateTime
    {
        get { return (DateTime)GetValue(DateTimeProperty); }
        set { SetValue(DateTimeProperty, value); OnPropertyChanged("DateTime"); }
    }

    private TimeSpan _time
    {
        get
        {
            return TimeSpan.FromTicks(DateTime.Ticks);
        }
        set
        {
            DateTime = new DateTime(DateTime.Date.Ticks).AddTicks(value.Ticks);
        }
    }

    private DateTime _date
    {
        get
        {
            return DateTime.Date;
        }
        set
        {
            DateTime = new DateTime(DateTime.TimeOfDay.Ticks).AddTicks(value.Ticks);
        }
    }

    BindableProperty DateTimeProperty = BindableProperty.Create("DateTime", typeof(DateTime), typeof(DateTimePicker2), DateTime.Now, BindingMode.TwoWay, propertyChanged: DTPropertyChanged);

    public DateTimePicker2()
    {
        BindingContext = this;

        Content = new StackLayout()
        {
            Children =
            {
                _datePicker,
                _timePicker,
                _entry
            }
        };

        _datePicker.SetBinding<DateTimePicker2>(DatePicker.DateProperty, p => p._date);
        _timePicker.SetBinding<DateTimePicker2>(TimePicker.TimeProperty, p => p._time);
        _timePicker.Unfocused += (sender, args) => _time = _timePicker.Time;
        _datePicker.Focused += (s, a) => UpdateEntryText();

        GestureRecognizers.Add(new TapGestureRecognizer()
        {
            Command = new Command(() => _datePicker.Focus())
        });
        _entry.Focused += (sender, args) =>
        {
            Device.BeginInvokeOnMainThread(() => _datePicker.Focus());
        };
        _datePicker.Unfocused += (sender, args) =>
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                _timePicker.Focus();
                _date = _datePicker.Date;
                UpdateEntryText();
            });
        };
    }

    private void UpdateEntryText()
    {
        _entry.Text = DateTime.ToString(StringFormat);
    }

    static void DTPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var timePicker = (bindable as DateTimePicker2);
        timePicker.UpdateEntryText();
    }
}

在 Xaml 中的用法:

<StackLayout>
        <local:DateTimePicker2></local:DateTimePicker2>
    </StackLayout>

【讨论】:

  • 谢谢,我有一个问题。既然 SetBinding(property, lambda) 已经过时了,如何进行相应的更改才能使其生效?
  • 如何使用 Nullable DateTime?
  • 如何在我的 xaml 中使用可绑定属性?如果我添加以下标记,它会在我构建项目时出现错误 错误:未找到属性、BindableProperty 或事件对于“日期时间:或值和属性之间的类型不匹配
  • @Serena _datePicker.SetBinding(DatePicker.DateProperty, nameof(_date)); _timePicker.SetBinding(TimePicker.TimeProperty, nameof(_time));
  • @Jiren 将 BindableProperty 设为公共静态并删除 BindingContext = this 行
【解决方案2】:

在 Xamarin.forms Android 上,您可以尝试以下代码。

创建一个 DateTimePicker.cs 类。

 public class DateTimePicker : Entry, INotifyPropertyChanged
{
    public DatePicker _datePicker { get; private set; } = new DatePicker() { MinimumDate = DateTime.Today, IsVisible = false };
    public TimePicker _timePicker { get; private set; } = new TimePicker() { IsVisible = false };
    string _stringFormat { get; set; }
    public string StringFormat { get { return _stringFormat ?? "dd/MM/yyyy HH:mm"; } set { _stringFormat = value; } }
    public DateTime DateTime
    {
        get { return (DateTime)GetValue(DateTimeProperty); }
        set { SetValue(DateTimeProperty, value); OnPropertyChanged("DateTime"); }
    }

    private TimeSpan _time
    {
        get
        {
            return TimeSpan.FromTicks(DateTime.Ticks);
        }
        set
        {
            DateTime = new DateTime(DateTime.Date.Ticks).AddTicks(value.Ticks);
        }
    }

    private DateTime _date
    {
        get
        {
            return DateTime.Date;
        }
        set
        {
            DateTime = new DateTime(DateTime.TimeOfDay.Ticks).AddTicks(value.Ticks);
        }
    }

    BindableProperty DateTimeProperty = BindableProperty.Create("DateTime", typeof(DateTime), typeof(DateTimePicker), DateTime.Now, BindingMode.TwoWay, propertyChanged: DTPropertyChanged);

    public DateTimePicker()
    {
        BindingContext = this;
        _datePicker.SetBinding<DateTimePicker>(DatePicker.DateProperty, p => p._date);
        _timePicker.SetBinding<DateTimePicker>(TimePicker.TimeProperty, p => p._time);
        _timePicker.Unfocused += (sender, args) => _time = _timePicker.Time;
        _datePicker.Focused += (s, a) => UpdateEntryText();

        GestureRecognizers.Add(new TapGestureRecognizer()
        {
            Command = new Command(() => _datePicker.Focus())
        });
        Focused += (sender, args) =>
        {
            Device.BeginInvokeOnMainThread(() => _datePicker.Focus());
        };
        _datePicker.Unfocused += (sender, args) =>
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                _timePicker.Focus();
                _date = _datePicker.Date;
                UpdateEntryText();
            });
        };
    }

    private void UpdateEntryText()
    {
        Text = DateTime.ToString(StringFormat);
    }

    static void DTPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var timePicker = (bindable as DateTimePicker);
        timePicker.UpdateEntryText();
    }
}

App.xaml.cs 中的用法

   var dtPicker = new DateTimePicker()
        {
            VerticalOptions = LayoutOptions.FillAndExpand,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            StringFormat = "HH:mm dd/MM/yyyy"
        };

        MainPage = new ContentPage
        {
            Content = new StackLayout
            {
                VerticalOptions = LayoutOptions.Center,
                Children = {
                    dtPicker._datePicker,
                    dtPicker._timePicker,
                    dtPicker
                },
                BackgroundColor = Color.Aqua
            }
        };

【讨论】:

  • 您好,这可行,但我想在 xaml 中调用它。这可能吗?我尝试在 xaml 中调用控件,但它不起作用
  • 嗨,谢谢!:) 只是为了澄清一下,我是否必须使用 app.xaml.cs 中的代码才能使其工作?因为我的不起作用,因为我只使用 xaml 来调用函数
  • 不,xaml 也可以。为方便起见,我只是在 app.xaml.cs 中进行测试,Updated 中的 xaml 中的代码运行良好。
  • 我的不工作..不确定是不是因为我使用了 xmlns:control 代替?
  • 错误是什么?您是否在 ContentPage 中添加了 xmlns:local="clr-namespace:XamarinDemo.Controls(DateTimePicker 类所在的位置)?
【解决方案3】:

为了方便任何想要将 DateTimePicker 与 XAML 集成(带有绑定)一起使用的人,我将 Wendy Zhang 的原始帖子中的答案、其下方的 cmets 以及来自 csharpdude77 的问题 (Custom control not being set to content width) 合并。

代码:

public class DateTimePicker : ContentView, INotifyPropertyChanged
{
    private Entry _entry { get; set; } = new Entry() { WidthRequest = 300 };
    private DatePicker _datePicker { get; set; } = new DatePicker() { MinimumDate = DateTime.Today, IsVisible = false };
    private TimePicker _timePicker { get; set; } = new TimePicker() { IsVisible = false };
    private string _stringFormat { get; set; }
    private TimeSpan _time
    {
        get { return TimeSpan.FromTicks(DateTime.Ticks); }
        set { DateTime = new DateTime(DateTime.Date.Ticks).AddTicks(value.Ticks); }
    }
    private DateTime _date
    {
        get { return DateTime.Date; }
        set { DateTime = new DateTime(DateTime.TimeOfDay.Ticks).AddTicks(value.Ticks); }
    }

    public string StringFormat { get { return _stringFormat ?? "dd/MM/yyyy HH:mm"; } set { _stringFormat = value; } }
    public DateTime DateTime
    {
        get { return (DateTime)GetValue(DateTimeProperty); }
        set { SetValue(DateTimeProperty, value); OnPropertyChanged(nameof(DateTime)); }
    }

    public static BindableProperty DateTimeProperty = BindableProperty.Create(nameof(DateTime), typeof(DateTime), typeof(DateTimePicker), DateTime.Now, BindingMode.TwoWay, propertyChanged: DTPropertyChanged);

    public DateTimePicker()
    {
        Content = new StackLayout()
        {
            Children =
            {
                _datePicker,
                _timePicker,
                _entry
            }
        };

        _datePicker.SetBinding(DatePicker.DateProperty, nameof(_date));
        _timePicker.SetBinding(TimePicker.TimeProperty, nameof(_time));
        _timePicker.Unfocused += (sender, args) => _time = _timePicker.Time;
        _datePicker.Focused += (s, a) => UpdateEntryText();

        GestureRecognizers.Add(new TapGestureRecognizer()
        {
            Command = new Command(() => _datePicker.Focus())
        });

        _entry.Focused += (sender, args) =>
        {
            Device.BeginInvokeOnMainThread(() => _datePicker.Focus());
        };

        _datePicker.Unfocused += (sender, args) =>
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                _timePicker.Focus();
                _date = _datePicker.Date;
                UpdateEntryText();
            });
        };
    }

    private void UpdateEntryText()
    {
        _entry.Text = DateTime.ToString(StringFormat);
    }

    private static void DTPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var timePicker = bindable as DateTimePicker;
        timePicker.UpdateEntryText();
    }
}

XAML 用法示例:

        <StackLayout>
            <local:DateTimePicker DateTime="{Binding Source={RelativeSource AncestorType={x:Type class:NewRitViewModel}}, Path=DateTime}" StringFormat="dd-MM-yyyy HH:mm"></local:DateTimePicker>
        </StackLayout>

【讨论】:

    【解决方案4】:

    这是我的代码

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    
        void OnDateSelected(object sender, DateChangedEventArgs args)
        {
            Recalculate();
        }
    
        void OnSwitchToggled(object sender, ToggledEventArgs args)
        {
            Recalculate();
        }
    
        void Recalculate()
        {
            TimeSpan timeSpan = endDatePicker.Date - startDatePicker.Date +
            (includeSwitch.IsToggled ? TimeSpan.FromDays(1) : TimeSpan.Zero);
    
            resultLabel.Text = String.Format("{0} day{1} between dates",
                                            timeSpan.Days, timeSpan.Days == 1 ? "" : "s");
        }
    }
    

    【讨论】:

      【解决方案5】:

      我附上了日期时间选择器的代码

      <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:local="clr-namespace:DaysBetweenDates"
               x:Class="DaysBetweenDates.MainPage">
      <ContentPage.Padding>
      
          <OnPlatform x:TypeArguments="Thickness">
              <On Platform="iOS" Value="0, 20, 0, 0" />
          </OnPlatform>
      </ContentPage.Padding>
      
      <StackLayout Margin="10">
          <Label Text="Days Between Dates"
                 Style="{DynamicResource TitleStyle}"
                 Margin="0, 20"
                 HorizontalTextAlignment="Center" />
      
          <Label Text="Start Date:" />
      
          <DatePicker x:Name="startDatePicker"
                      Format="D"
                      Margin="30, 0, 0, 30"
                      DateSelected="OnDateSelected" />
      
          <Label Text="End Date:" />
      
          <DatePicker x:Name="endDatePicker"
                      MinimumDate="{Binding Source={x:Reference startDatePicker},
                                            Path=Date}"
                      Format="D"
                      Margin="30, 0, 0, 30"
                      DateSelected="OnDateSelected" />
      
          <StackLayout Orientation="Horizontal"
                       Margin="0, 0, 0, 30">
              <Label Text="Include both days in total: "
                     VerticalOptions="Center" />
              <Switch x:Name="includeSwitch"
                      Toggled="OnSwitchToggled" />
          </StackLayout>
      
          <Label x:Name="resultLabel"
                 FontAttributes="Bold"
                 HorizontalTextAlignment="Center" />
      <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
               xmlns:local="clr-namespace:DaysBetweenDates"
               x:Class="DaysBetweenDates.MainPage">
      <ContentPage.Padding>
          <OnPlatform x:TypeArguments="Thickness">
              <On Platform="iOS" Value="0, 20, 0, 0" />
          </OnPlatform>
      </ContentPage.Padding>
      
      
      <StackLayout Margin="10">
          <Label Text="Days Between Dates"
                 Style="{DynamicResource TitleStyle}"
                 Margin="0, 20"
                 HorizontalTextAlignment="Center" />
      
          <Label Text="Start Date:" />
      
          <DatePicker x:Name="startDatePicker"
                      Format="D"
                      Margin="30, 0, 0, 30"
                      DateSelected="OnDateSelected" />
      
          <Label Text="End Date:" />
      
          <DatePicker x:Name="endDatePicker"
                      MinimumDate="{Binding Source={x:Reference startDatePicker},
                                            Path=Date}"
                      Format="D"
                      Margin="30, 0, 0, 30"
                      DateSelected="OnDateSelected" />
      
          <StackLayout Orientation="Horizontal"
                       Margin="0, 0, 0, 30">
              <Label Text="Include both days in total: "
                     VerticalOptions="Center" />
              <Switch x:Name="includeSwitch"
                      Toggled="OnSwitchToggled" />
          </StackLayout>
      
          <Label x:Name="resultLabel"
                 FontAttributes="Bold"
                 HorizontalTextAlignment="Center" />
      
      </StackLayout>
      

      【讨论】:

        猜你喜欢
        • 2019-08-05
        • 2020-11-24
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 2015-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多