Ошибка: не могу выбрать даты на DatePicker, которые выходят за пределы плавающей надстройки VSTO

зарегистрировал проблему с Microsoft здесь-Repro доступен для загрузки: https://connect.microsoft.com/VisualStudio/feedback/details/741454/value-change-event-doesnt-fire-for-datetimepicker-controls-used-in-vsto-add-ins

Если вы помещаете DateTimePicker в плавающую надстройку Excel VSTO и располагаете ее так, когда календарь падает, он находится за пределами края надстройки, см. здесь:

enter image description here

выбор любой из дат обведенный зеленым цветом работает, как и ожидалось, но при нажатии на любые даты, обведенные красным, он просто закрывает выпадающий календарь и не устанавливает дату!

кто-нибудь знает как я могу это исправить?

редактировать

это так пользователь испытал проблему с использованием WPF: VSTO WPF ContextMenu.MenuItem нажмите вне панели задач не поднят

enter image description here

ответ на этот вопрос показывает с докладом чтобы подключиться некоторое время назад, но до сих пор нет решения с VSTO 4.0 SP1: https://connect.microsoft.com/VisualStudio/feedback/details/432998/excel-2007-vsto-custom-task-pane-with-wpf-context-menu-has-focus-problems

одним из обходных путей является использование DispatcherFrame для перекачки сообщений и подписки на gotfocusevent и LostFocusEvent для меню. http://blogs.msdn.com/b/vsod/archive/2009/12/16/excel-2007-wpf-events-are-not-fired-for-items-that-overlap-excel-ui-for-wpf-context-menus.aspx но это все код WPF для меню не является решением для Winform DateTimePicker.

Repro для Microsoft Connect:

Новый Проект > Надстройка Excel 2010 использование панели задач; с помощью Microsoft.Офис.Ядро;

пространство имен ExcelAddIn2 { публичный частичный класс ThisAddIn { TaskPaneView MyTaskView = null; Microsoft.Офис.Инструменты.CustomTaskPane MyTaskPane = null;

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    //setup custom taskpane
    MyTaskView = new TaskPaneView();
    MyTaskView.currentInstance = Globals.ThisAddIn.Application;
    MyTaskPane = this.CustomTaskPanes.Add(MyTaskView, "MyTaskView");
    MyTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionFloating;
    MyTaskPane.DockPositionRestrict = MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
    MyTaskPane.Visible = true;
}
}

меню Файл > Добавить > новый проект > библиотека классов > именованная область задач

затем в проекте TaskPane создайте пользовательский элемент управления под названием TaskPaneView

public partial class TaskPaneView : UserControl
{
    public TaskPaneView()
    {
        InitializeComponent();
    }

    public Microsoft.Office.Interop.Excel.Application currentInstance { get; set; }

    public TaskPaneCtrl getTaskPaneCtrl
    {
        get { return this.taskPaneCtrl1; }
    }  

}

затем создайте пользовательский элемент управления с помощью DateTimePicker, убедитесь, что элемент управления Calendar расположен в правом нижнем углу пользовательского элемента управления

public partial class TaskPaneCtrl : UserControl
{
public TaskPaneCtrl()
{
    InitializeComponent();
}
}

в библиотеке классов TaskPane Ссылка на взаимодействие Excel (например c:Program файлы x86Microsoft Visual Studio 14.0средства Visual Studio для OfficePIAOffice14Microsoft.Офис.Взаимодействие.Превосходить.файл DLL.)

построить решение. Комментируя части, которые не работают. Построить Решение.

Теперь перетащите TaskPaneCtrl на TaskPaneView и раскомментируйте вещь, которая не удалось скомпилировать.

enter image description here

F5 и нажмите элемент управления Calendar, теперь попробуйте выбрать дату, которая находится вне области панели задач. событие изменения значения не срабатывает, оно ведет себя как щелчок вне календаря!

Примечание: я попробовал выпадающий список, который выпадает из-под контроля, но его события срабатывают!

2 ответов


"плавающий" является ключом к проблеме здесь. Что никогда не является проблемой, так это то, что вы полагаетесь на насос сообщений в Excel для отправки сообщений Windows, сообщений, которые заставляют эти элементы управления отвечать на ввод. Это идет не так в WPF, как Winforms, у них есть свой собственный цикл отправки, который фильтрует сообщения перед их доставкой в окно. Ключевые вещи, которые идут не так, когда их соответствующий диспетчер не используется,-это такие вещи, как табуляция и короткие нажатия клавиш.

и тогда некоторые, такого рода проблемы будут вызваны Excel делает свою собственную фильтрацию перед отправкой сообщений. Я бы предположил, что функция защиты от вредоносных программ Microsoft всегда беспокоится о программах, возящихся с приложениями Office.

решение Winforms такое же, как обходной путь WPF, вам нужно прокачать свой собственный цикл сообщений. Это требует некоторой операции, DateTimePicker не будет сотрудничать, так как он не позволяет отменить его выпадающее событие, и оно поднимается после календарь уже показали. Обходной путь глупый, но эффективный, добавьте кнопку в свою форму, которая выглядит так же, как стрелка раскрывающегося списка на DTP, и сделайте ее перекрывающей стрелку, чтобы она была нажата вместо стрелки.

некоторый пример кода для получения кнопки для перекрытия стрелки раскрывающегося списка:

    public Form1() {
        InitializeComponent();
        var btn = new Button();
        btn.BackgroundImage = Properties.Resources.DropdownArrow;
        btn.FlatStyle = FlatStyle.Flat;
        btn.BackColor = Color.FromKnownColor(KnownColor.Window);
        btn.Parent = dateTimePicker1;
        btn.Dock = DockStyle.Right;
        btn.Click += showMonthCalendar;
        dateTimePicker1.Resize += delegate {
            btn.Width = btn.Height = dateTimePicker1.ClientSize.Height;
        };
    }

обработчик событий Click должен показать диалоговое окно, содержащее MonthCalendar:

    private void showMonthCalendar(object sender, EventArgs e) {
        dateTimePicker1.Focus();
        using (var dlg = new CalendarForm()) {
            dlg.DateSelected += new DateRangeEventHandler((s, ea) => dateTimePicker1.Value = ea.Start);
            dlg.Location = dateTimePicker1.PointToScreen(new Point(0, dateTimePicker1.Height));
            dlg.ShowDialog(this);
        }
    }

С CalendarForm форму добавления это без границ и содержит только MonthCalendar:

public partial class CalendarForm : Form {
    public event DateRangeEventHandler DateSelected;

    public CalendarForm() {
        InitializeComponent();
        this.StartPosition = FormStartPosition.Manual;
        monthCalendar1.Resize += delegate {
            this.ClientSize = monthCalendar1.Size;
        };
        monthCalendar1.DateSelected += monthCalendar1_DateSelected;
    }

    void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e) {
        if (DateSelected != null) DateSelected(this, e);
        this.DialogResult = DialogResult.OK;
    }
}

предположения:
Ошибка возникает, потому что поверхность datetimepicker не отображается до тех пор, пока не будет отправлено сообщение щелчка.

следующие шаги, чтобы ответить:
Если доступно, попробуйте протестировать с некоторыми элементами управления 3rd party date time picker. Я понимаю, что это не полный ответ, так как я еще не знаю, исправит ли он вашу проблему.

другой возможный ответ: Измените размер панели задач в соответствии с элементом управления. Это разберется с ошибкой, но выглядит немного странно от пользователя точка зрения.