c# - with - wpf toolkit calendar




Have to click away twice from Calendar in WPF (4)

I had the same issue weeks ago, you can use DatePicker which is a control that contains a Calendar, the calendar is displayed once the user clicks a button and when you select a date its automatically closed, the DatePicker Contains also a textbox when the date is visible, you can make it ReadOnly if you want: here a sample code for using DatePicker:

<DatePicker Name="TestDatePicker" Width="120" Height="25" >
        <DatePicker.Resources>
            <Style TargetType="DatePickerTextBox">
                <Setter Property="IsReadOnly" Value="True"></Setter>
                <Setter Property="Text" Value="Select a Date"></Setter>
            </Style>
        </DatePicker.Resources>
</DatePicker>    

Hope this helps.

result :

Edit 2: Thank you all for your feedback. I solved the problem by adding this to my SelectedDatesChanged event:

Mouse.Capture(null);

When I select a date in my calendar, I want to click my "Go" button. However, I need to click the "Go" button twice: once to de-focus the calendar, and again to actually press it. The mouse leave event does not trigger on the calendar if an item is selected inside of it, and Keyboard.ClearFocus() does not de-focus it either.

Please, how can I get rid of the calendar's focus whenever I select a date? Thank you!

Edit: Clicking the "Go" button next was merely an example; if I want to select a textbox and I have just selected a date, I would also have to click twice to enter the textbox. The main issue is that, once the calendar is interacted with, it must be clicked out of once before interacting with any other elements.


I handled SelectedDatesChanged event and I was displaying property OriginalSource of MouseButtonEventArgs. When you pick a date it displays Path, Rectangle and so on but when you pick for instance button or whatever beyond calendar it displays precisely System.Windows.Controls.Primitives.CalendarItem. Apparently calendar needs one more click in order to transfer mouse to another UIelement. My idea was to invoke event after first click on calendar so that it could lost capture right away.

public static class CalendarM
{
    private static Button tempButton;
    public static bool GetRemoveProperty(DependencyObject obj)
    {
        return (bool)obj.GetValue(RemoveFocusProperty);
    }

    public static void SetRemoveProperty(DependencyObject obj, bool value)
    {
        obj.SetValue(RemoveFocusProperty, value);
    }
    public static readonly DependencyProperty RemoveFocusProperty = DependencyProperty.RegisterAttached("RemoveFocus", typeof(bool), typeof(CalendarM),
        new FrameworkPropertyMetadata(new PropertyChangedCallback((x, y) =>
        {
            if (x is Calendar && GetRemoveProperty((DependencyObject)x))
            {
                tempButton = new Button() { Width = 0, Height = 0 };
                ((System.Windows.Controls.Panel)((FrameworkElement)x).Parent).Children.Add(tempButton);
                tempButton.Click += (s1, s2) =>
                {
                };
                ((Calendar)x).SelectedDatesChanged += CalendarM_SelectedDatesChanged;
            }
        })));
    static void CalendarM_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
    {
        tempButton.RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left) { RoutedEvent = Button.MouseDownEvent });
    }
}

I created UIelement(in this case button) to invoke its MouseDown event. I had to add it to Panel(setting visibility did not work), otherwise event does not allow to invoke itself. Now when you click calendar it invokes tempButton.Click, it looses capture and when you press your Button "GO" it does not require clicking two times. I know it is a dirty way out, but working.

  <StackPanel>
        <Calendar local:CalendarM.RemoveProperty="True"/>
        <Button Content="Go" Click="but_Click"/>
        <TextBox Text="Text"/>
    </StackPanel>
</StackPanel>

If you select the same date then SelectedDatesChanged won't be raised and you will see the same issue where you need to click twice.

Ideally you should hook to GotMouseCapture event and release the mouse capture from original sender to avoid any mouse captures by calendar control.

private void calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
    UIElement originalElement = e.OriginalSource as UIElement;
    if (originalElement != null)
    {
        originalElement.ReleaseMouseCapture();
    }
}

Note - You can extract out this in behavior as well by using attached property like mentioned in another answer.


Releasing all mouse clicks in SelectedDatesChanged or GotMouseCapture will break the navigation between months on the calendar control. As pointed out in another answer, SelectedDatesChanged does not fire when the same date is selected.

So I used GotMouseCapture and only released the mouse focus when the clicked UIElement was a calendar day. It fixes the focus issue and doesn't break the rest of the control.

private void Calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
    UIElement originalElement = e.OriginalSource as UIElement;
    if (originalElement is CalendarDayButton || originalElement is CalendarItem)
    {
        originalElement.ReleaseMouseCapture();
    }
}




focus