10

我在这里记录了 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 浮动加载项中并定位它,以便当日历下降时,它位于加载项的边缘之外,请参见此处:

在此处输入图像描述

选择绿色圈出的任何日期都可以按预期工作,但是当单击红色圈出的任何日期时,它只会关闭日历下拉菜单并且不会设置日期!

有谁知道我该如何解决这个问题?

编辑

此 SO 用户在使用 WPF 时遇到了问题: VSTO WPF ContextMenu.MenuItem Click outside a TaskPane not raise

在此处输入图像描述

该问题的答案显示该问题被报告为连接一段时间,但仍然没有解决 VSTO 4.0 SP1 的问题:https ://connect.microsoft.com/VisualStudio/feedback/details/432998/excel-2007-vsto-custom-任务窗格与 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 的解决方案。

Microsoft Connect 的复制:

新建项目 > Excel 2010 加载项

using TaskPane;
using Microsoft.Office.Core;

namespace ExcelAddIn2
{
public partial class ThisAddIn
{
    TaskPaneView MyTaskView = null;
    Microsoft.Office.Tools.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

然后在 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 创建一个用户控件,确保日历控件位于用户控件的右下角

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

在 TaskPane 类库中引用 Excel 互操作(例如 c:\Program Files x86\Microsoft Visual Studio 14.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll)。

构建解决方案。注释掉不起作用的部分。构建解决方案。

现在将 TaskPaneCtrl 拖放到 TaskPaneView 上并取消注释无法编译的内容。

在此处输入图像描述

F5 并单击日历控件,现在尝试选择任务窗格区域之外的日期。没有值更改事件触发,它的行为就像在日历外单击!

注意:我尝试了一个脱离控件的下拉列表,但它的事件确实发生了!

4

2 回答 2

7

“浮动”是这里问题的关键。依赖 Excel 中的消息泵来发送 Windows 消息,这些消息使这些控件响应输入,这从来都不是问题(偶尔会造成奇怪的事情)。这在 WPF 中和 Winforms 一样出错,它们有自己的调度循环,可以在消息传递到窗口之前过滤消息。不使用各自的调度程序时出现问题的关键事情是制表符和快捷键。

然后一些,这种问题将由 Excel 在发送消息之前进行自己的过滤引起。我猜是反恶意软件功能,微软永远担心程序会干扰 Office 应用程序。

Winforms 解决方案与 WPF 解决方法相同,您需要自己泵送消息循环。这需要一些手术,DateTimePicker 不会合作,因为它不允许取消其 DropDown 事件,并且它在日历已经显示后被引发。解决方法是愚蠢但有效的,在表单中添加一个按钮,看起来就像 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;
    }
}
于 2012-05-12T13:34:21.190 回答
2

推测:
该错误的发生是因为 datetimepicker 的表面直到单击消息发送后才呈现。

回答的后续步骤:
如果可用,请尝试使用一些第 3 方日期时间选择器控件进行测试。我意识到这不是一个完整的答案,因为我还不知道它是否会解决您的问题。

其他可能的答案:调整任务窗格的大小以适应控件。这将解决错误,但从用户的角度来看有点奇怪。

于 2012-05-10T05:54:12.733 回答