必须从 WPF 中的日历中单击两次
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25352961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Have to click away twice from Calendar in WPF
提问by user3076399
Edit 2: Thank you all for your feedback. I solved the problem by adding this to my SelectedDatesChanged event:
编辑2:感谢大家的反馈。我通过将它添加到我的 SelectedDatesChanged 事件解决了这个问题:
Mouse.Capture(null);
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.
当我在日历中选择一个日期时,我想单击“开始”按钮。但是,我需要单击“开始”按钮两次:一次使日历散焦,再次实际按下它。如果在日历中选择了一个项目,则鼠标离开事件不会在日历上触发,并且 Keyboard.ClearFocus() 也不会使其失去焦点。
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.
编辑:接下来单击“开始”按钮只是一个例子;如果我想选择一个文本框而我刚刚选择了一个日期,我还必须单击两次才能进入该文本框。主要问题是,一旦与日历交互,就必须在与任何其他元素交互之前单击一次。
回答by user3076399
I solved the problem by adding this to my SelectedDatesChanged event:
我通过将它添加到我的 SelectedDatesChanged 事件解决了这个问题:
Mouse.Capture(null);
Mouse.Capture(null);
回答by Millie Smith
Releasing all mouse clicks in SelectedDatesChangedor GotMouseCapturewill break the navigation between months on the calendar control. As pointed out in another answer, SelectedDatesChangeddoes not fire when the same date is selected.
释放所有鼠标点击SelectedDatesChanged或GotMouseCapture将破坏日历控件上月份之间的导航。正如在另一个答案中指出的那样,SelectedDatesChanged选择相同日期时不会触发。
So I used GotMouseCaptureand 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.
因此GotMouseCapture,当单击的 UIElement 是日历日时,我使用并且仅释放鼠标焦点。它修复了焦点问题并且不会破坏其余的控制。
private void Calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
UIElement originalElement = e.OriginalSource as UIElement;
if (originalElement is CalendarDayButton || originalElement is CalendarItem)
{
originalElement.ReleaseMouseCapture();
}
}
回答by Rohit Vats
If you select the same date then SelectedDatesChangedwon't be raised and you will see the same issue where you need to click twice.
如果您选择相同的日期,则SelectedDatesChanged不会出现,并且您将看到需要单击两次的相同问题。
Ideally you should hook to GotMouseCaptureevent and release the mouse capture from original senderto avoid any mouse captures by calendar control.
理想情况下,您应该挂钩GotMouseCapture事件并从原始发件人处释放鼠标捕获,以避免日历控件捕获任何鼠标。
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.
注意- 您也可以通过使用另一个答案中提到的附加属性来提取行为。
回答by sa_ddam213
So it seems the Calendarcaptures the Mouse exclusively, One option could be to make a AttachedPropertyto release the capture when the user clicks
因此似乎Calendar专门捕获鼠标,一种选择是AttachedProperty在用户单击时释放捕获
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 AttachedPropertyto your Calenderand it will defocus once an item is selected.
现在您可以将它应用AttachedProperty到您的Calender,一旦选择了一个项目,它就会散焦。
Full Example:
完整示例:
Xaml:
Xml:
<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);
}
};
}
}
}
}
回答by Redaa
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,它是一个包含日历的控件,一旦用户单击按钮就会显示日历,当您选择一个自动关闭的日期时,DatePicker 还包含一个文本框是可见的,如果需要,您可以将其设为只读:这里是使用 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 :
结果 :


回答by Maximus
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.
我处理了 SelectedDatesChanged 事件,并且显示了 MouseButtonEventArgs 的属性 OriginalSource。当您选择一个日期时,它会显示路径、矩形等,但是当您选择例如按钮或日历之外的任何内容时,它会精确地显示 System.Windows.Controls.Primitives.CalendarItem。显然日历需要再点击一次才能将鼠标转移到另一个 UIelement。我的想法是在第一次点击日历后调用事件,以便它可以立即丢失捕获。
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.
我创建了 UIelement(在本例中是按钮)来调用它的 MouseDown 事件。我不得不将它添加到面板(设置可见性不起作用),否则事件不允许调用自身。现在,当您单击日历时,它会调用 tempButton.Click,它会丢失捕获,并且当您按下按钮“GO”时,它不需要单击两次。我知道这是一个肮脏的出路,但工作。
<StackPanel>
<Calendar local:CalendarM.RemoveProperty="True"/>
<Button Content="Go" Click="but_Click"/>
<TextBox Text="Text"/>
</StackPanel>
</StackPanel>
回答by Franz
Found this
找到这个
Code:
代码:
public void ReleaseMouse()
{
if (Mouse.Captured is CalendarItem) Mouse.Capture(null);
}
XAML:
XAML:
<Calendar PreviewMouseUp="ReleaseMouse" />
Source: https://quick-geek.github.io/answers/819560/index.html
来源:https: //quick-geek.github.io/answers/819560/index.html
Easy and seems to have no drawbacks:
简单,似乎没有缺点:

