C# 必须在WPF中从日历中单击两次
编辑2:谢谢大家的反馈。我通过将此添加到SelectedDatesChanged事件中解决了此问题:C# 必须在WPF中从日历中单击两次,c#,wpf,focus,C#,Wpf,Focus,编辑2:谢谢大家的反馈。我通过将此添加到SelectedDatesChanged事件中解决了此问题: Mouse.Capture(空) 当我在日历中选择日期时,我想单击我的“开始”按钮。但是,我需要单击“Go”按钮两次:一次取消日历的焦点,另一次实际按下它。如果在日历中选择了某个项目,则不会在日历上触发鼠标离开事件,并且Keyboard.ClearFocus()也不会解除该项目的焦点 请问,每当我选择一个日期时,我如何摆脱日历的焦点? 谢谢大家! 编辑:点击“下一步”按钮只是一个例子;如果我想选
Mouse.Capture(空)代码>
当我在日历中选择日期时,我想单击我的“开始”按钮。但是,我需要单击“Go”按钮两次:一次取消日历的焦点,另一次实际按下它。如果在日历中选择了某个项目,则不会在日历上触发鼠标离开事件,并且Keyboard.ClearFocus()也不会解除该项目的焦点
请问,每当我选择一个日期时,我如何摆脱日历的焦点?
谢谢大家!
编辑:点击“下一步”按钮只是一个例子;如果我想选择一个文本框,而我刚刚选择了一个日期,我还必须单击两次才能输入文本框。主要问题是,一旦与日历交互,在与任何其他元素交互之前必须一次性单击它。我在几周前也遇到过同样的问题,您可以使用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>
希望这有帮助
结果:
因此,日历
似乎只捕获鼠标,一个选项是在用户单击时制作一个附件属性
来释放捕获
例如:
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);
}
};
}
}
}
现在,您可以将此AttachedProperty
应用于您的日历
,一旦选中某个项目,它将散焦
完整示例:
Xaml:
代码:
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
命名空间WpfApplication2
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
}
公共静态类CalandarHelper
{
公共静态只读从属属性SingleClickDisfocus属性=
DependencyProperty.RegisterAttached(“SingleClickDefocus”)、typeof(bool)、typeof(Calendar)
,新的FrameworkPropertyMetadata(false,新的PropertyChangedCallback(SingleClickDisfocusChanged));
公共静态bool GetSingleClick离焦(DependencyObject obj){
返回(bool)对象获取值(SingleClickDisfocusProperty);
}
公共静态无效设置SingleClick离焦(DependencyObject obj,布尔值){
对象设置值(SingleClickDisfocus属性,值);
}
私有静态void SingleClickDisfocusChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
如果(d是日历)
{
日历=d作为日历;
calendar.PreviewMouseDown+=(a、b)=>
{
if(Mouse.Captured为日历| | Mouse.Captured为System.Windows.Controls.Primitives.CalendarItem)
{
鼠标捕捉(空);
}
};
}
}
}
}
我处理了SelectedDatesChanged事件,并显示了MouseButtonEventArgs的属性源。当您选择日期时,它会显示路径、矩形等,但当您选择例如按钮或日历以外的任何内容时,它会精确地显示System.Windows.Controls.Primitives.CalendarItem。显然,日历需要再点击一次才能将鼠标转移到另一个元素。我的想法是在第一次单击日历后调用事件,这样它就可以立即丢失捕获
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 });
}
}
我创建了UIelement(在本例中为button)来调用其MouseDown事件。我必须将它添加到面板中(设置可见性不起作用),否则事件不允许调用自身。现在,当您单击日历时,它会调用tempButton。单击,它会释放捕获,当您按下按钮“GO”时,它不需要单击两次。我知道这是一个肮脏的出路,但工作
<StackPanel>
<Calendar local:CalendarM.RemoveProperty="True"/>
<Button Content="Go" Click="but_Click"/>
<TextBox Text="Text"/>
</StackPanel>
</StackPanel>
我通过将此添加到我的SelectedDatesChanged事件中解决了问题:
Mouse.Capture(空)
如果选择相同的日期,则不会出现已选择日期更改的问题,您将看到需要单击两次的相同问题
理想情况下,您应该钩住GotMouseCapture
事件,并从原始发件人释放鼠标捕获,以避免通过日历控件捕获任何鼠标
private void calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
UIElement originalElement = e.OriginalSource as UIElement;
if (originalElement != null)
{
originalElement.ReleaseMouseCapture();
}
}
注意-您也可以使用另一个答案中提到的附加属性在行为中提取该属性。在SelectedDatesChanged
或GotMouseCapture
中释放所有鼠标单击将中断日历控件上月份之间的导航。正如另一个答案所指出的,SelectedDatesChanged
在选择相同日期时不会触发
因此,我使用了GotMouseCapture
,仅当单击的ui元素是日历日时才释放鼠标焦点。它修复了焦点问题,不会破坏控件的其余部分
private void Calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
UIElement originalElement = e.OriginalSource as UIElement;
if (originalElement is CalendarDayButton || originalElement is CalendarItem)
{
originalElement.ReleaseMouseCapture();
}
}
找到这个
代码:
XAML:
资料来源:
简单而且似乎没有缺点:您希望在日历中选择日期后立即通过Go按钮捕获鼠标吗?您是否尝试过将日历
和按钮
组合在同一个聚焦镜
中?如果您使用MVVM模式,这是一个非常好的选择。非常感谢。这会破坏月份导航按钮,并且在选择相同日期时不起作用。请看我的答案。这会破坏月份导航按钮,并且不会
private void calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
UIElement originalElement = e.OriginalSource as UIElement;
if (originalElement != null)
{
originalElement.ReleaseMouseCapture();
}
}
private void Calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
UIElement originalElement = e.OriginalSource as UIElement;
if (originalElement is CalendarDayButton || originalElement is CalendarItem)
{
originalElement.ReleaseMouseCapture();
}
}
public void ReleaseMouse()
{
if (Mouse.Captured is CalendarItem) Mouse.Capture(null);
}
<Calendar PreviewMouseUp="ReleaseMouse" />