Пользовательский элемент управления DateTimePicker .NET MAUI (справка)

Я надеялся получить помощь с пользовательским элементом управления DateTimePicker в .NET MAUI. Я новичок в MAUI и разработке в целом, поэтому заранее извиняюсь, если мой вопрос не ясен.

Я пытаюсь выполнить следующее:

  1. Пользователь выбирает запись, и появляются средства выбора даты и времени.
  2. После выбора даты и времени средства выбора исчезают, а метка записи заполняется выбранной датой и временем.

Я пытался использовать несфокусированное событие в средствах выбора, чтобы скрыть их, но когда вы выбираете средство выбора времени (в качестве примера), оно исчезает до того, как время будет полностью выбрано, и метка не обновляется соответствующим образом. Ниже то, что у меня есть до сих пор, любая помощь или предложения очень ценятся!

XAML:

      <?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:inputLayout="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="TestApplication.View.DateTimePicker">

    <VerticalStackLayout Padding="10">
        <inputLayout:SfTextInputLayout     x:Name="EntryField"
                                           IsHintAlwaysFloated="True"
                                           ContainerType="Outlined"
                                           ContainerBackground="Transparent">
 <inputLayout:SfTextInputLayout.GestureRecognizers>
                <TapGestureRecognizer Tapped="Entry_Tapped" />
            </inputLayout:SfTextInputLayout.GestureRecognizers>
            <Entry IsReadOnly="True" x:Name="entry"/>
            <inputLayout:SfTextInputLayout.LeadingView>
                <ImageButton Source="calendar.png"/>
            </inputLayout:SfTextInputLayout.LeadingView>
        </inputLayout:SfTextInputLayout>
        <HorizontalStackLayout Spacing="10" IsVisible="False" x:Name="picker" HorizontalOptions="Center">
            <DatePicker x:Name="datePicker" DateSelected="DatePicker_DateSelected" Format="MM/dd/yyyy" Unfocused="Picker_Unfocused"/>
            <TimePicker x:Name="timePicker" Focused="TimePicker_TimeSelected" Unfocused="Picker_Unfocused"/>
        </HorizontalStackLayout>
    </VerticalStackLayout>   
</ContentView>

Код позади:

      using System.ComponentModel;

namespace TestApplication.View;

public partial class DateTimePicker : ContentView, INotifyPropertyChanged
{
    public DateTimePicker()
    {
        InitializeComponent();
    }

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

    public event EventHandler DateTimeUpdated;

    public event PropertyChangedEventHandler PropertyChanged;

    public DateTime DateTime
    {
        get => (DateTime)GetValue(DateTimeProperty);
        set
        {
            SetValue(DateTimeProperty, value);
            OnPropertyChanged("DateTime");
            DateTimeUpdated?.Invoke(this, EventArgs.Empty);
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        DateTimeUpdated?.Invoke(this, EventArgs.Empty);
    }

    private void DatePicker_DateSelected(object sender, DateChangedEventArgs e)
    {
        DateTime = new DateTime(e.NewDate.Year, e.NewDate.Month, e.NewDate.Day, timePicker.Time.Hours, timePicker.Time.Minutes, 0);
        entry.Text = DateTime.ToString("MM/dd/yyyy h:mm tt");
        DateTimeUpdated?.Invoke(this, EventArgs.Empty);
    }

    private void TimePicker_TimeSelected(object sender, FocusEventArgs e)
    {
        DateTime = new DateTime(DateTime.Year, DateTime.Month, DateTime.Day, timePicker.Time.Hours, timePicker.Time.Minutes, 0);
        entry.Text = DateTime.ToString("MM/dd/yyyy h:mm tt");
        DateTimeUpdated?.Invoke(this, EventArgs.Empty);
    }

   private void Entry_Tapped(object sender, EventArgs e)
    {
        picker.IsVisible = !picker.IsVisible;
    }

    private void Picker_Unfocused(object sender, FocusEventArgs e)
    {
        picker.IsVisible = false;
    }
} 

1 ответ

Вы можете попробовать использовать MVVM для достижения:

      public class MyVM : INotifyPropertyChanged
{
private DateTime _selectedDate;
private TimeSpan _selectedTime; 
public MyVM()
    {         
        _selectedDate = DateTime.Today;        
        _selectedTime = DateTime.Now.TimeOfDay;     
    }     
    public DateTime SelectedDate     
    {         
        get { return _selectedDate; }         
        set {          
            if (_selectedDate != value)            
            {               
                _selectedDate = value; 
                OnPropertyChanged(nameof(SelectedDate));         
                OnPropertyChanged(nameof(SelectedDateTime));    
                OnPropertyChanged(nameof(SelectedDateTimeString));   
            }     
        }    
    }    
    public TimeSpan SelectedTime 
    {     
        get { return _selectedTime; }   
        set       
        {         
            if (_selectedTime != value)   
            {             
                _selectedTime = value; 
                OnPropertyChanged(nameof(SelectedTime));       
                OnPropertyChanged(nameof(SelectedDateTime)); 
                OnPropertyChanged(nameof(SelectedDateTimeString));   
            }       
        }    
    }   
    public DateTime SelectedDateTime   
    {        
        get { return new DateTime(SelectedDate.Year, SelectedDate.Month, SelectedDate.Day, SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds); } 
    }    
    public string SelectedDateTimeString   
    {        
        get { return SelectedDateTime.ToString("MM/dd/yyyy hh:mm tt"); }    
    }   
    public event PropertyChangedEventHandler PropertyChanged;  
    protected virtual void OnPropertyChanged(string propertyName)    
    {         
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));     
    } 
} 

Xaml:

          <StackLayout>

    <Entry x:Name="entry"
           Text="{Binding SelectedDateTimeString}"
           Focused="OnEntryFocused"/>

    <Grid x:Name="pickerLayout" IsVisible="false">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <DatePicker Grid.Row="0" Date="{Binding SelectedDate}" />
        <TimePicker Grid.Row="1" Time="{Binding SelectedTime}" />
        <Button Grid.Row="2" Text="OK" Clicked="OnPickerOKClicked"/>
    </Grid>
</StackLayout> 

Файл Xamal.cs:

      public partial class MyPicker : ContentView
{
    MyVM vm = new MyVM();
    public MyPicker()
    {
        InitializeComponent();
        BindingContext = vm;
    }

    private async void OnEntryFocused(object sender, FocusEventArgs e)
    {

        entry.IsVisible = false;
        pickerLayout.IsVisible = true;
        await Task.Run(() => WaitForChangedResult());
    }

    private async void OnPickerOKClicked(object sender,EventArgs e)
    {
        pickerLayout.IsVisible = false;
        entry.IsVisible = true;
        OnPropertyChanged(nameof(vm.SelectedDateTimeString));
    }

    private void WaitForChangedResult() {
        while (pickerLayout.IsVisible)
        {
            Thread.Sleep(100);
        }
    }
}
Другие вопросы по тегам