Home > Software design >  DatePicker Template, Binding to SelectedDate not Working
DatePicker Template, Binding to SelectedDate not Working

Time:01-10

I'm trying to change the DatePicker template. I almost made the design with the help of Custom Control. But not only did I spend 2 days of my life on this, it also does not work incorrectly. The SelectedDateChenged call change event is called multiple times. I decided to change the approach, rewrite the template. Now there was a problem that Binding does not work. That is, there are changes in the calendar. I see them, the event is called, the SelectedDate changes there, but the Binding does not work. Please help me figure it out, I'm attaching the source code of the template and converters.

DatePicker Template

<Style x:Key="DatePickerStyle" TargetType="{x:Type DatePicker}">
        <Style.Resources>
            <conv:MonthToGenitiveMonthNameConverter x:Key="MonthToGenitiveMonthNameConverter"/>
            <conv:MonthToAbbreviatedMonthNameConverter x:Key="MonthToAbbreviatedMonthNameConverter"/>
            <conv:DayToDayNameConverter x:Key="DayToDayNameConverter"/>
            <conv:DateToTwoDigitDateConverter x:Key="DateToTwoDigitDateConverter"/>
        </Style.Resources>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Height" Value="70"/>
        <Setter Property="Width" Value="500"/>
        <Setter Property="IsTodayHighlighted" Value="True"/>
        <Setter Property="SelectedDateFormat" Value="Short"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Padding" Value="2"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DatePicker}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <Grid x:Name="PART_Root" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                            <Grid  HorizontalAlignment="Stretch">
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                                    <TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding Foreground}" FontSize="50" Text="{Binding Path=SelectedDate.Day, Converter={StaticResource DateToTwoDigitDateConverter}}" />
                                    <StackPanel Margin="10,2,0,2" VerticalAlignment="Center" >
                                        <TextBlock Foreground="{TemplateBinding Foreground}" FontSize="24" FontWeight="Bold" Text="{Binding Path=SelectedDate.Month, Converter={StaticResource MonthToGenitiveMonthNameConverter}}"/>
                                        <TextBlock Foreground="{TemplateBinding Foreground}" FontSize="14" Text="{Binding Path=SelectedDate.DayOfWeek, Converter={StaticResource DayToDayNameConverter}}"/>
                                    </StackPanel>
                                    <TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding Foreground}" FontSize="50" Text="{Binding Path=SelectedDate.Year}" />
                                    <TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding Foreground}" FontSize="50" Text="г." />
                                </StackPanel>
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                                    <Button Name="PART_Button" Style="{StaticResource ExtendedDataPickerButtonStyle}">
                                        <fa:IconImage Icon="Calendar"  Style="{StaticResource BigIconStyle}"/>
                                    </Button>
                                    <DatePickerTextBox x:Name="PART_TextBox" Visibility="Collapsed"/>
                                    <Popup x:Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_Button}" StaysOpen="False" 
                                           ui:PopupProperties.HorizontalPlacementAlignment="Center"
                                           ui:PopupProperties.VerticalOffset="2"/>
                                </StackPanel>
                            </Grid>
                        </Grid>
                    </Border>
                   
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Converters

    [ValueConversion(typeof(string), typeof(int))]
    class DateToTwoDigitDateConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int val = (int)value;
            if (((int)val / 10) > 0)
            {
                return value.ToString();
            }
            else 
            {
                return "0"   value.ToString();
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
 [ValueConversion(typeof(string), typeof(DayOfWeek))]
    class DayToDayNameConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return culture.DateTimeFormat.GetDayName((DayOfWeek)value).FirstCharToUpper();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
[ValueConversion(typeof(string), typeof(int))]
    class MonthToAbbreviatedMonthNameConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return culture.DateTimeFormat.GetAbbreviatedMonthName((int)value).FirstCharToUpper();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
[ValueConversion(typeof(string), typeof(int))]
    class MonthToGenitiveMonthNameConverter : IValueConverter
    {
        private const int ArrayZeroBasedConst = 1;
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        { 
            return culture.DateTimeFormat.MonthGenitiveNames[(int)value - ArrayZeroBasedConst].FirstCharToUpper();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    [ValueConversion(typeof(string), typeof(int))]
    class MonthToNominativeMonthNameConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return culture.DateTimeFormat.GetMonthName((int)value).FirstCharToUpper();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

I don't know what to try anymore.

The code from this site, for which many thanks, I have already checked, just in case, it's not in it.

ui:PopupProperties.HorizontalPlacementAlignment="Center"
ui:PopupProperties.VerticalOffset="2"

I am trying to remake DatePicker and Calendar. I don't have access to the Internal methods in the source code, and there are quite a few of them. I can publish the source codes of the last iteration of programming, but it turned out to be a very large heap with truncated functionality.

CodePudding user response:

I still solved this problem. I will not publish the entire code, I will publish only significant changes. Firstly, Custom Control appeared again, only very minimalistic.

public class ModernDatePicker : DatePicker, IDisposable
{
    public static readonly DependencyProperty VisualizatedDateProperty = DependencyProperty.Register(nameof(VisualizatedDate), typeof(DateTime), typeof(ModernDatePicker),
                           new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public DateTime VisualizatedDate
    {
        get { return (DateTime)GetValue(VisualizatedDateProperty); }
        set { SetValue(VisualizatedDateProperty, value); }
    }

    static ModernDatePicker()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ModernDatePicker), new FrameworkPropertyMetadata(typeof(ModernDatePicker)));
    }

    public ModernDatePicker()
    {
        Loaded  = ModernDatePicker_Loaded;
        SelectedDateChanged  = ModernDatePicker_SelectedDateChanged;
    }

    private void ModernDatePicker_Loaded(object sender, RoutedEventArgs e)
    {
        if (this.SelectedDate == null)
        {
            SelectedDate = VisualizatedDate;
        }
    }

    private void ModernDatePicker_SelectedDateChanged(object? sender, SelectionChangedEventArgs e)
    {
        ModernDatePicker mdp = (ModernDatePicker)sender;
        if (mdp.SelectedDate != null)
        {
            VisualizatedDate = mdp.SelectedDate.Value;
        }
    }

}

    public void Dispose()
    {
        SelectedDateChanged -= ModernDatePicker_SelectedDateChanged;
        Loaded -= ModernDatePicker_Loaded;
    }

SelectDate is a DateTime? type, which does not allow you to get the value immediately at startup, you had to use a DependencyProperty, with a DateTime type, in order to be able to use Binding. Secondly, changes in XAML.

<Style TargetType="{x:Type cc:ModernDatePicker}">
        <Style.Resources>
            <conv:MonthToGenitiveMonthNameConverter x:Key="MonthToGenitiveMonthNameConverter"/>
            <conv:DayToDayNameConverter x:Key="DayToDayNameConverter"/>
            <conv:DateToTwoDigitDateConverter x:Key="DateToTwoDigitDateConverter"/>
        </Style.Resources>
        <Setter Property="Foreground" Value="#223266"/>
        <Setter Property="IsTodayHighlighted" Value="True"/>
        <Setter Property="CalendarStyle" Value="{DynamicResource ModernCalendarStyle}"/>
        <Setter Property="SelectedDateFormat" Value="Short"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="SubForeground" Value="#9eabe2"/>
        <Setter Property="OtherForeground" Value="White"/>
        <Setter Property="Padding" Value="2"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type cc:ModernDatePicker}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <Grid x:Name="PART_Root" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                            <Grid  HorizontalAlignment="Stretch">
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                                    <TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding OtherForeground}" FontSize="50" Text="{Binding VisualizatedDate.Day, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}},Converter = {StaticResource DateToTwoDigitDateConverter}}" />
                                    <StackPanel Margin="10,2,0,2" VerticalAlignment="Center" >
                                        <TextBlock Foreground="{TemplateBinding OtherForeground}" FontSize="24" FontWeight="Bold" Text="{Binding VisualizatedDate.Month, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}}, Converter={StaticResource MonthToGenitiveMonthNameConverter}}"/>
                                        <TextBlock Foreground="{TemplateBinding SubForeground}" FontSize="14" Text="{Binding VisualizatedDate.DayOfWeek, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}}, Converter={StaticResource DayToDayNameConverter}}"/>
                                    </StackPanel>
                                    <TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding OtherForeground}" FontSize="50" Text="{Binding VisualizatedDate.Year, RelativeSource={RelativeSource AncestorType={x:Type cc:ModernDatePicker}}}" />
                                    <TextBlock Margin="5 0 0 0" Foreground="{TemplateBinding OtherForeground}" FontSize="50" Text="г." />
                                </StackPanel>
                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                                    <Button Name="PART_Button" Style="{StaticResource ExtendedDataPickerButtonStyle}">
                                        <fa:IconImage Icon="Calendar"  Style="{StaticResource BigIconStyle}"/>
                                    </Button>
                                    <DatePickerTextBox x:Name="PART_TextBox" Visibility="Collapsed"/>
                                    <Popup x:Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_Button}" StaysOpen="False" 
                                           ui:PopupProperties.HorizontalPlacementAlignment="Center"
                                           ui:PopupProperties.VerticalOffset="2"/>
                                </StackPanel>
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>

Well, in fact, by analogy

  • Related