2012-05-10 1 views
9

protokolliert das Problem mit Microsoft hier - die Repro zum Download zur Verfügung: https://connect.microsoft.com/VisualStudio/feedback/details/741454/value-change-event-doesnt-fire-for-datetimepicker-controls-used-in-vsto-add-insBUG: Cant wählen Daten auf einem Datepicker, die außerhalb eines Sturzes schwebenden VSTO Add-In

Wenn Sie ein Datetimepicker in einem Excel VSTO setzen floating hinzufügen -In und so positionieren, wenn der Kalender nach unten fällt, ist es außerhalb der Kante des Add-in finden sie hier:

enter image description here

einem der Termine die Wahl in den grünen Arbeiten eingekreist wie erwartet, aber wenn Wenn Sie auf ein Datum klicken, das rot eingekreist ist, wird nur das Kalender-Drop-Down-Menü geschlossen und das Datum nicht eingestellt!

Weiß jemand, wie ich das beheben kann?

EDIT

Dieser SO Benutzer hat das Problem mit WPF erfahren: VSTO WPF ContextMenu.MenuItem Click outside a TaskPane not raised

enter image description here

Die Antwort auf diese Frage zeigt das Problem gemeldet wurde eine Weile zurück zu verbinden, aber immer noch nicht Lösung mit 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

Eine der Problemumgehungen ist die Verwendung der DispatcherFrame, um Nachrichten zu pumpen und GotFocusEvent und LostFocusEvent für das Menü zu abonnieren. 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 aber das ist alles WPF-Code für Menüs nicht eine Lösung für WinForm DateTimePicker.

Repro für Microsoft Connect:

Neues Projekt> Excel 2010 Add-In

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; 
} 

Datei-Menü> Hinzufügen> Neues Projekt> Klassenbibliothek> genannt TaskPane

dann in der TaskPane Projekt erstellen ein Benutzersteuerelement namens 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; } 
    } 

} 

Next ein User Control mit einem Datetime erstellen, stellen Sie sicher, dass die Kalender-Steuerelement in Richtung der unteren rechten Ecke des Steuer Benutzer befindet

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

F5 und die Kalender-Steuerelement klicken, wird nun versuchen, ein Datum zu wählen, die außerhalb der ist Aufgabenbereich. Kein Wert Das Ereignis wird ausgelöst, es verhält sich wie ein Klick außerhalb des Kalenders!

Hinweis: Ich habe versucht, eine Drop-Down-Liste, die von der Kontrolle fällt, aber ihre Ereignisse DO FIRE!

Antwort

7

"Floating" ist hier der Schlüssel zum Problem. Was immer kein Problem ist, ist, dass Sie sich auf die Nachrichtenpumpe in Excel verlassen, um Windows-Nachrichten zu versenden, die Nachrichten, die diese Steuerelemente auf Eingaben reagieren lassen. Das ist in WPF genauso falsch wie in Winforms. Sie haben ihre eigene Dispatch-Schleife, die Nachrichten filtert, bevor sie an das Fenster gesendet werden. Die wichtigsten Dinge, die schief gehen, wenn ihr jeweiliger Dispatcher nicht verwendet wird, sind Dinge wie Tabbing und Tastaturkürzel.

Und dann einige, diese Art von Problem würde durch Excel seine eigene Filterung vor dem Versenden von Nachrichten verursacht induziert werden. Ich denke an eine Anti-Malware-Funktion, Microsoft ist immer besorgt über Programme, die mit Office-Apps herumspielen.

Die Winforms-Lösung ist dieselbe wie die WPF-Problemumgehung, Sie müssen Ihre eigene Nachrichtenschleife pumpen. Das erfordert eine Operation, DateTimePicker wird nicht kooperieren, da es nicht erlaubt, dass sein DropDown-Ereignis abgebrochen wird und es ausgelöst wird , nachdem der Kalender bereits angezeigt wird. Die Problemumgehung ist albern, aber effektiv, fügen Sie Ihrem Formular eine Schaltfläche hinzu, die genau wie der Dropdown-Pfeil auf dem DTP aussieht und es so überlagert, dass der Pfeil anstelle des Pfeils angeklickt wird.

Einige Beispiel-Code für die Schaltfläche immer den Dropdown-Pfeil zu überlappen:

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; 
     }; 
    } 

Die Click-Ereignishandler muss einen Dialog zeigen, dass eine Monthcalendar enthält:

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); 
     } 
    } 

Mit CalendarForm ein Formular, das Sie fügen Sie hinzu das ist randlos und enthält nur einen 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; 
    } 
} 
+1

+1 Brilliant! Liest wie ein SOX (Visual KB?), Wenn das funktioniert, wenn ich es am Montag versuche, können keine Worte meine Dankbarkeit ausdrücken. –

+1

Niveau der ehrfürchtigen überschritten. Netter Hans –

2

spekulation:
Der Fehler tritt auf, weil die Oberfläche des datetimepicker erst wiedergegeben wird, nachdem die Click-Nachricht gesendet wurde.

Nächste Schritte zur Beantwortung:
Falls verfügbar, versuchen Sie es mit einigen Datumsauswahlsteuerungen von Drittherstellern. Ich weiß, dies ist keine vollständige Antwort, da ich noch nicht weiß, ob es Ihr Problem beheben wird.

Andere mögliche Antwort: Ändern Sie die Größe der Taskleiste auf das Steuerelement. Dies wird den Fehler beheben, aber aus Benutzersicht ein wenig seltsam aussehen.

Verwandte Themen