Необходимо дважды щелкнуть дважды из "Календарь" в WPF

Редактировать 2: Спасибо всем за ваши отзывы. Я решил проблему, добавив это в событие SelectedDatesChanged:

Mouse.Capture(null);

Когда я выбираю дату в своем календаре, я хочу нажать кнопку "Перейти" . Тем не менее, мне нужно дважды нажать кнопку "Перейти" : один раз для дефокусировки календаря и снова для фактического нажатия. Событие выключения мыши не запускается в календаре, если в нем выбран элемент, а Keyboard.ClearFocus() также не дефокусирует его.

Пожалуйста, как я могу избавиться от фокуса календаря, когда я выбираю дату? Спасибо!

Изменить: нажатие кнопки "Перейти" было просто примером; если я хочу выбрать текстовое поле, и я только что выбрал дату, мне также нужно дважды щелкнуть, чтобы ввести текстовое поле. Основная проблема заключается в том, что после взаимодействия календаря его необходимо щелкнуть один раз перед взаимодействием с любыми другими элементами.

Ответ 1

Я решил проблему, добавив это в событие SelectedDatesChanged:

Mouse.Capture(null);

Ответ 2

Если вы выберете ту же дату, то SelectedDatesChanged не будет поднята, и вы увидите ту же проблему, где вам нужно дважды щелкнуть.

В идеале вы должны подключиться к событию GotMouseCapture и освободить захват мыши от исходного отправителя, чтобы избежать захвата мыши календарным управлением.

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

Примечание. Вы также можете извлечь это в поведении, используя прикрепленное свойство, как указано в другом ответе.

Ответ 3

Итак, кажется, что 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);
                    }
                };
            }
        }
    }
}

Ответ 4

У меня была такая же проблема несколько недель назад, вы можете использовать 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>    

Надеюсь, что это поможет.

результат:

result

Ответ 5

Я обработал событие 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>