DateTimeEditBox - Focused calendar date when value is null

Editors for WPF Forum

Posted 10 years ago by John Schreifels
Version: 9.2.0511
Avatar
In the case of a DateTimeEditBox having a null value is there a way to set the the date that is focused when the calendar is opened?

It seems that it defaults focus to the last date value assigned to the control. If no date value was previously set it defaults to today. For example if a value of 01/01/2001 is assigned and then subsequently the value is set to null when the calendar is opened the focused date will be 01/01/2001 instead of today.

Comments (4)

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi John,

There's not really an easy way to set the selected/focused date in the month calendar when the Value is null. We could probably hook the calendar up to the InitialValue property when Value is null, since that is effectively the default value used by the DateTimeEditBox.

Would this work for you or did you have something else in mind for how it would work?


Actipro Software Support

Posted 10 years ago by John Schreifels
Avatar
It's not entirely clear by reading the help content how the InitialValue and IsInitialValueAutoUpdated properties are expected to be used. If you could provide additional information on these properties, especially Is InitialValueAutoUpdated, that might be helpful.

Ideally for our situation, I'd like to be able to set a property that specifies the default focus date when the Value property is null. When the control has a value I believe the calendar should continue to have focus on the selected date.

I believe your suggestion of using the InitalValue property as the focus value when Value is null makes sense to me and would solve the problem.

Thanks for the quick response!
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi John,

After looking at this for a while, we are still trying to find a clean solution that make sense. I've marked down a TODO item to look at this further, but in the interim this attached behavior should accomplish what you want:
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
using ActiproSoftware.Windows.Controls.Editors;
using ActiproSoftware.Windows.Media;

namespace SampleCode {

    /// <summary>
    /// Provides attached behaviors for <see cref="DateTimeEditBox"/> controls to flash the associated tab.
    /// </summary>
    public static class CustomActiveDateBehavior {

        #region Dependency Properties

        /// <summary>
        /// Identifies the <c>ActiveDate</c> attached dependency property.  This field is read-only.
        /// </summary>
        /// <value>The identifier for the <c>ActiveDate</c> attached dependency property.</value>
        public static readonly DependencyProperty ActiveDateProperty = DependencyProperty.RegisterAttached("ActiveDate",
            typeof(DateTime?), typeof(CustomActiveDateBehavior), new FrameworkPropertyMetadata(null, OnActiveDatePropertyValueChanged));

        #endregion // Dependency Properties

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        #region NON-PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Called when <see cref="ActiveDateProperty"/> is changed.
        /// </summary>
        /// <param name="d">The dependency object that was changed.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnActiveDatePropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            DateTimeEditBox control = d as DateTimeEditBox;
            if (null == control)
                return;

            if (null != e.NewValue)
                control.DropDownOpened += new RoutedEventHandler(OnDateTimeEditBoxDropDownOpened);
            else
                control.DropDownOpened -= new RoutedEventHandler(OnDateTimeEditBoxDropDownOpened);
        }

        /// <summary>
        /// Handles the <c>DropDownOpened</c> event of the <c>DateTimeEditBox</c> control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private static void OnDateTimeEditBoxDropDownOpened(object sender, RoutedEventArgs e) {
            DateTimeEditBox control = sender as DateTimeEditBox;
            if (null == control || null != control.Value)
                return;

            DateTime? activeDate = GetActiveDate(control);
            if (null == activeDate)
                return;

            control.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, (DispatcherOperationCallback)delegate {
                Popup popup = VisualTreeHelperExtended.GetFirstDescendant(control, typeof(Popup)) as Popup;
                if (null != popup) {
                    Visual visual = popup.Child as Visual;
                    if (null != visual) {
                        MonthCalendar monthCalendar = VisualTreeHelperExtended.GetFirstDescendant(visual, typeof(MonthCalendar)) as MonthCalendar;
                        if (null != monthCalendar) {
                            monthCalendar.AreTransitionAnimationsEnabled = false;
                            try {
                                monthCalendar.ActiveDate = activeDate.Value;
                            }
                            finally {
                                monthCalendar.AreTransitionAnimationsEnabled = true;
                            }
                        }
                    }
                }
                return null;
            }, null);
        }

        #endregion // NON-PUBLIC PROCEDURES

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        #region PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Gets the value of the <see cref="ActiveDateProperty"/> attached property for a specified <see cref="DateTimeEditBox"/>.
        /// </summary>
        /// <param name="obj">The object to which the attached property is retrieved.</param>
        /// <returns>
        /// The desired active date.
        /// </returns>
        public static DateTime? GetActiveDate(DateTimeEditBox obj) {
            if (null == obj) throw new ArgumentNullException("obj");
            return (DateTime?)obj.GetValue(CustomActiveDateBehavior.ActiveDateProperty);
        }
        /// <summary>
        /// Sets the value of the <see cref="ActiveDateProperty"/> attached property to a specified <see cref="DateTimeEditBox"/>.
        /// </summary>
        /// <param name="obj">The object to which the attached property is written.</param>
        /// <param name="value">
        /// A value indicating whether the desired active date.
        /// </param>
        public static void SetActiveDate(DateTimeEditBox obj, DateTime? value) {
            if (null == obj) throw new ArgumentNullException("obj");
            obj.SetValue(CustomActiveDateBehavior.ActiveDateProperty, value);
        }

        #endregion // PUBLIC PROCEDURES
    }
}
So you'd just set the attached ActiveDate to your desired date and it would pass that along to the MonthCalendar. Hope this helps.


Actipro Software Support

Posted 10 years ago by John Schreifels
Avatar
The attached behavior seems to do the trick.

Thanks,

John
The latest build of this product (v2019.1 build 0683) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.