C# 错误:无法在日期选择器上选择不属于浮动VSTO加载项的日期

C# 错误:无法在日期选择器上选择不属于浮动VSTO加载项的日期,c#,.net,excel,vsto,datetimepicker,C#,.net,Excel,Vsto,Datetimepicker,我在此处向Microsoft记录了该问题-可下载该复制程序: 如果在Excel VSTO浮动加载项中放置DateTimePicker,并在日历下拉时将其放置在加载项边缘之外,请参见此处: 按预期选择绿色圆圈中的任何日期都有效,但单击红色圆圈中的任何日期时,它只会关闭日历下拉列表,而不会设置日期 有人知道我怎么解决这个问题吗 编辑 该用户在使用WPF时遇到了以下问题: 该问题的答案显示,前一段时间报告了该问题,但仍然没有VSTO 4.0 SP1的解决方案: 解决方法之一是使用Dispatcher

我在此处向Microsoft记录了该问题-可下载该复制程序:

如果在Excel VSTO浮动加载项中放置DateTimePicker,并在日历下拉时将其放置在加载项边缘之外,请参见此处:

按预期选择绿色圆圈中的任何日期都有效,但单击红色圆圈中的任何日期时,它只会关闭日历下拉列表,而不会设置日期

有人知道我怎么解决这个问题吗

编辑 该用户在使用WPF时遇到了以下问题:

该问题的答案显示,前一段时间报告了该问题,但仍然没有VSTO 4.0 SP1的解决方案:

解决方法之一是使用DispatcherFrame发送消息,并订阅菜单的GotFocusEvent和LostFocusEvent。但这都是菜单的WPF代码,而不是WinFormDateTimePicker的解决方案

针对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项目中创建一个名为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();
}
}
在任务窗格类库中,参考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并单击日历控件,现在尝试选择任务窗格区域之外的日期。不触发值更改事件,其行为类似于在日历外单击

注意:我尝试了一个从控件上掉下来的下拉列表,但是它的事件确实触发了

猜测: 出现此错误的原因是,直到发送单击消息之后,才呈现datetimepicker的曲面

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

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

浮动是解决这个问题的关键。偶尔会有一些奇怪的事情发生的问题是,依赖Excel中的消息泵来发送Windows消息,这些消息使这些控件对输入做出响应。这在WPF和Winforms中都是错误的,它们有自己的分派循环,在消息传递到窗口之前过滤消息。当它们各自的调度器未被使用时,出现问题的关键是诸如制表符和快捷键击之类的东西

还有一些,这种问题可能是由Excel在发送消息之前自己进行过滤引起的。我猜在反恶意软件功能方面,微软一直担心程序会干扰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;
        };
    }
单击事件处理程序需要显示包含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);
        }
    }
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;
    }
}
CalendarForm是您添加的一个无边界表单,仅包含一个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);
        }
    }
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;
    }
}

+1太棒了!读起来像是SOX的Visual KB?,如果我在周一试用时能用它,没有任何语言可以表达我的感激之情。超棒的水平。不错,汉斯