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 solved the problem by adding this to my SelectedDatesChanged event:
Mouse.Capture(null);
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();
}
}
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.
So it seems the Calendar
captures the Mouse exclusively, One option could be to make a AttachedProperty
to release the capture when the user clicks
Example:
public static class CalandarHelper
{
public static readonly DependencyProperty SingleClickDefocusProperty =
DependencyProperty.RegisterAttached("SingleClickDefocus", typeof(bool), typeof(Calendar)
, new FrameworkPropertyMetadata(false, new PropertyChangedCallback(SingleClickDefocusChanged)));
public static bool GetSingleClickDefocus(DependencyObject obj) {
return (bool)obj.GetValue(SingleClickDefocusProperty);
}
public static void SetSingleClickDefocus(DependencyObject obj, bool value) {
obj.SetValue(SingleClickDefocusProperty, value);
}
private static void SingleClickDefocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Calendar)
{
Calendar calendar = d as Calendar;
calendar.PreviewMouseDown += (a, b) =>
{
if (Mouse.Captured is Calendar || Mouse.Captured is System.Windows.Controls.Primitives.CalendarItem)
{
Mouse.Capture(null);
}
};
}
}
}
Now you can apply this AttachedProperty
to your Calender
and it will defocus once an item is selected.
Full Example:
Xaml:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helpers="clr-namespace:WpfApplication2"
Title="MainWindow" Width="300" >
<StackPanel>
<Calendar helpers:CalandarHelper.SingleClickDefocus="True" />
<TextBox />
</StackPanel>
</Window>
Code:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public static class CalandarHelper
{
public static readonly DependencyProperty SingleClickDefocusProperty =
DependencyProperty.RegisterAttached("SingleClickDefocus", typeof(bool), typeof(Calendar)
, new FrameworkPropertyMetadata(false, new PropertyChangedCallback(SingleClickDefocusChanged)));
public static bool GetSingleClickDefocus(DependencyObject obj) {
return (bool)obj.GetValue(SingleClickDefocusProperty);
}
public static void SetSingleClickDefocus(DependencyObject obj, bool value) {
obj.SetValue(SingleClickDefocusProperty, value);
}
private static void SingleClickDefocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Calendar)
{
Calendar calendar = d as Calendar;
calendar.PreviewMouseDown += (a, b) =>
{
if (Mouse.Captured is Calendar || Mouse.Captured is System.Windows.Controls.Primitives.CalendarItem)
{
Mouse.Capture(null);
}
};
}
}
}
}
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 :
Found this
Code:
public void ReleaseMouse()
{
if (Mouse.Captured is CalendarItem) Mouse.Capture(null);
}
XAML:
<Calendar PreviewMouseUp="ReleaseMouse" />
Source: https://quick-geek.github.io/answers/819560/index.html
Easy and seems to have no drawbacks:
Other answers had always some glitches with changing months and days. The only thing working for me I've found here
private void Calendar_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (Mouse.Captured is CalendarItem)
{
Mouse.Capture(null);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With