Création d'un sélecteur de dates et heures inspiré d'Element UI en WPF

Pour répondre à des besoins de sélection de plages horaires similaires au composant DateTimePicker d'Element UI, une solution personnalisée sous WPF s'avère nécessaire. Le DatePicker natif, composé d'un DatePickerTextBox, d'un Button et d'un Calendar généré dynamiquement, ne permet pas une personnalisation directe via son template.

Approche technique

Un UserControl DateTimePicker est implémenté avec quatre propriétés de dépendance :

  • HoverStart/HoverEnd : contrôlent les dates de début/fin dans le calendrier
  • DateTimeRangeStart/DateTimeRangeEnd : gèrent les valeurs sélectionnées

Structure XAML

<Grid>
    <Border>
        <StackPanel Orientation="Horizontal">
            <Custom:HintTextBox x:Name="StartDateField" 
                GotFocus="OnDateFieldFocused">
                <Custom:HintTextBox.Text>
                    <Binding Path="DateTimeRangeStart" 
                             StringFormat="yyyy-MM-dd HH:mm">
                        <Binding.ValidationRules>
                            <validators:DateRangeRule 
                                 MaxValue="{Binding Text, ElementName=EndDateField}"/>
                        </Binding.ValidationRules>
                    </Binding>
                </Custom:HintTextBox.Text>
            </Custom:HintTextBox>
            
            <TextBlock Text="~"/>
            
            <Custom:HintTextBox x:Name="EndDateField" 
                GotFocus="OnDateFieldFocused">
                <!-- Validation similaire -->
            </Custom:HintTextBox>
            
            <Custom:IconButton Click="ToggleCalendar"/>
        </StackPanel>
    </Border>
    
    <Popup x:Name="CalendarPanel">
        <Grid>
            <StackPanel Orientation="Horizontal">
                <Calendar x:Name="FirstCalendar" 
                          SelectionChanged="UpdateDateSelection"/>
                <Calendar x:Name="SecondCalendar" 
                          DisplayDate="{Binding DisplayDate, ElementName=FirstCalendar}" />
            </StackPanel>
            
            <StackPanel Grid.Row="1">
                <TextBlock Text="Heure début:"/>
                <ComboBox x:Name="HourStart" ItemsSource="{Binding Hours}"/>
                <ComboBox x:Name="MinuteStart" ItemsSource="{Binding Minutes}"/>
                
                <TextBlock Text="Heure fin:"/>
                <ComboBox x:Name="HourEnd"/>
                <ComboBox x:Name="MinuteEnd"/>
            </StackPanel>
            
            <StackPanel Grid.Row="2" Orientation="Horizontal">
                <Button Content="Effacer" Click="ResetSelection"/>
                <Button Content="Valider" Click="ConfirmSelection"/>
            </StackPanel>
        </Grid>
    </Popup>
</Grid>

Personnalisation du calendrier

Le style des jours utilise un MultiBinding pour gérer l'apparenec des plages sélectionnées :

<Style TargetType="CalendarDayButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Border x:Name="RangeHighlight" 
                            Visibility="{Binding Converter={StaticDateRangeConverter}}">
                        <Border.CornerRadius>
                            <MultiBinding Converter="{StaticCornerRadiusConverter}"/>
                        </Border.CornerRadius>
                    </Border>
                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Convertisseur de plages

public class RangeConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object p, CultureInfo c)
    {
        if (values[0] is DateTime currentDay)
        {
            var start = (DateTime)values[1];
            var end = (DateTime)values[2];
            
            if (currentDay == start) return new CornerRadius(10, 0, 0, 10);
            if (currentDay == end) return new CornerRadius(0, 10, 10, 0);
        }
        return new CornerRadius(0);
    }
}

L'événemant SelectedDatesChanged met à jour les propriétés HoverStart et HoverEnd pour refléter la sélection.

Étiquettes: WPF XAML usercontrol calendar DateTimePicker

Publié le 1 juillet à 06h06