Ответ 1
Я решил проблему, добавив это в событие SelectedDatesChanged:
Mouse.Capture(null);
Редактировать 2: Спасибо всем за ваши отзывы. Я решил проблему, добавив это в событие SelectedDatesChanged:
Mouse.Capture(null);
Когда я выбираю дату в своем календаре, я хочу нажать кнопку "Перейти" . Тем не менее, мне нужно дважды нажать кнопку "Перейти" : один раз для дефокусировки календаря и снова для фактического нажатия. Событие выключения мыши не запускается в календаре, если в нем выбран элемент, а Keyboard.ClearFocus() также не дефокусирует его.
Пожалуйста, как я могу избавиться от фокуса календаря, когда я выбираю дату? Спасибо!
Изменить: нажатие кнопки "Перейти" было просто примером; если я хочу выбрать текстовое поле, и я только что выбрал дату, мне также нужно дважды щелкнуть, чтобы ввести текстовое поле. Основная проблема заключается в том, что после взаимодействия календаря его необходимо щелкнуть один раз перед взаимодействием с любыми другими элементами.
Я решил проблему, добавив это в событие SelectedDatesChanged:
Mouse.Capture(null);
Если вы выберете ту же дату, то SelectedDatesChanged
не будет поднята, и вы увидите ту же проблему, где вам нужно дважды щелкнуть.
В идеале вы должны подключиться к событию GotMouseCapture
и освободить захват мыши от исходного отправителя, чтобы избежать захвата мыши календарным управлением.
private void calendar_GotMouseCapture(object sender, MouseEventArgs e)
{
UIElement originalElement = e.OriginalSource as UIElement;
if (originalElement != null)
{
originalElement.ReleaseMouseCapture();
}
}
Примечание. Вы также можете извлечь это в поведении, используя прикрепленное свойство, как указано в другом ответе.
Итак, кажется, что Calendar
захватывает мышь исключительно, одним из вариантов может быть сделать AttachedProperty
, чтобы освободить захват, когда пользователь нажимает
Пример:
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
к вашему Calender
, и он будет дефокусироваться после выбора элемента.
Полный пример:
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>
код:
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);
}
};
}
}
}
}
У меня была такая же проблема несколько недель назад, вы можете использовать DatePicker, который является элементом управления, который содержит Календарь, календарь отображается, когда пользователь нажимает кнопку, и когда вы выбираете дату, которую она автоматически закрывает, DatePicker содержит также текстовое поле когда дата видна, вы можете сделать ее ReadOnly, если хотите: здесь пример кода для использования 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>
Надеюсь, что это поможет.
результат:
Я обработал событие SelectedDatesChanged, и я отображал свойство OriginalSource MouseButtonEventArgs. Когда вы выбираете дату, она отображает "Путь", "Прямоугольник" и т.д., Но когда вы выбираете для кнопки экземпляра или вне календаря, он точно отображает 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 });
}
}
Я создал UIelement (в этом случае кнопку), чтобы вызвать его событие MouseDown. Я должен был добавить его в Panel (настройка видимости не работала), иначе событие не позволяет вызывать себя. Теперь, когда вы нажимаете календарь, он вызывает tempButton.Click, он теряет захват, и когда вы нажимаете кнопку "GO", она не требует нажатия два раза. Я знаю, что это грязный выход, но работающий.
<StackPanel>
<Calendar local:CalendarM.RemoveProperty="True"/>
<Button Content="Go" Click="but_Click"/>
<TextBox Text="Text"/>
</StackPanel>
</StackPanel>