草庐IT

c# - 错误 : Can't choose dates on a DatePicker that fall outside a floating VSTO Add-In

coder 2024-06-03 原文

我在这里记录了 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 float 加载项中并将其放置在日历下拉时,它位于加载项的边缘之外,请参见此处:

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

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

编辑

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

该问题的答案显示该问题已报告为连接一段时间,但 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 的解决方案。

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 Interop(例如 c:\Program Files x86\Microsoft Visual Studio 14.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll)。

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

现在将 TaskPaneCtrl 拖放到 TaskPaneView 上,取消编译失败的注释。

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

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

最佳答案

“ float ”是这里问题的关键。永远不会出现问题(偶尔会导致奇怪的事情)是依靠 Excel 中的消息泵来发送 Windows 消息,这些消息使这些控件响应输入。这在 WPF 和 Winforms 中都是错误的,它们有自己的调度循环,在将消息传递到窗口之前过滤消息。不使用各自的调度程序时出错的关键问题是 Tab 键和快捷键等。

还有一些,这种问题会由 Excel 在发送消息之前进行自己的过滤引起。我猜想在反恶意软件功能方面,Microsoft 一直担心程序会干扰 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;
    }
}

关于c# - 错误 : Can't choose dates on a DatePicker that fall outside a floating VSTO Add-In,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10526118/

有关c# - 错误 : Can't choose dates on a DatePicker that fall outside a floating VSTO Add-In的更多相关文章

随机推荐