我在这里记录了 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/