2012-05-10 4 views
9

Logged il problema con Microsoft qui - la Repro è disponibile per il download: https://connect.microsoft.com/VisualStudio/feedback/details/741454/value-change-event-doesnt-fire-for-datetimepicker-controls-used-in-vsto-add-insERRORE: Cant scegliere date su un DatePicker che cadono fuori di un galleggiante VSTO Add-In

Se si mette un DateTimePicker in un VSTO Excel galleggiante Aggiungi -In e posizionarlo in modo che quando il calendario si abbassa, è al di fuori del bordo del componente aggiuntivo, vedere qui:

enter image description here

Scegliendo una delle date cerchiate nelle opere verdi come previsto, ma quando facendo clic su qualsiasi data cerchiata in rosso, si chiude semplicemente il calendario a tendina e non imposta la data!

Qualcuno sa come posso risolvere questo problema?

EDIT

Questo SO utente ha sperimentato il problema utilizzando WPF: VSTO WPF ContextMenu.MenuItem Click outside a TaskPane not raised

enter image description here

La risposta a questa domanda mostra il problema è stato segnalato per collegare un po 'indietro, ma ancora non soluzione 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

una delle soluzioni è quella di utilizzare il DispatcherFrame per pompare messaggi e iscriversi a GotFocusEvent e LostFocusEvent per il menu. 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 ma questo è tutto il codice WPF per menu non è una soluzione per Winform DateTimePicker.

Repro per Microsoft Connect:

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

Menu File> Aggiungi> Nuovo progetto> Libreria di classi> di nome TaskPane

Poi nel Il progetto TaskPane crea un controllo utente chiamato 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; } 
    } 

} 

Successivo creare un controllo utente con un DateTimePicker, assicurarsi che il controllo Calendar si trova verso il basso a destra del controllo utente

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

F5 e fare clic sul controllo di calendario, ora provare a selezionare una data che è al di fuori della area del taskpane. Nessun evento di modifica del valore, si comporta come un clic fuori dal calendario!

Nota: Ho provato un downlist goccia che cade il controllo, ma i suoi eventi FARE FUOCO!

risposta

7

"Floating" è la chiave del problema qui. Quello che non è mai un problema è che ci si basa sul messaggio pump in Excel per inviare messaggi Windows, i messaggi che rendono questi controlli rispondono all'input. Ciò non funziona in WPF tanto quanto in Winforms, hanno un proprio ciclo di invio che filtra i messaggi prima che vengano consegnati alla finestra. Le cose fondamentali che vanno male quando il loro rispettivo dispatcher non viene usato sono cose come tab e keystrokes.

E poi alcuni, questo tipo di problema sarebbe indotto da Excel a fare il proprio filtraggio prima di inviare messaggi. Immagino che con una funzione anti-malware, Microsoft sia per sempre preoccupata per i programmi che incasinano le app di Office.

La soluzione Winforms è la stessa del workflow di WPF, è necessario pompare il proprio loop di messaggi. Questo richiede un intervento chirurgico, DateTimePicker non ha intenzione di cooperare poiché non consente che il suo evento DropDown venga cancellato e viene sollevato dopo il il calendario è già mostrato. La soluzione alternativa è sciocca ma efficace, aggiungi un pulsante al tuo modulo che assomiglia alla freccia del menu a discesa sul DTP e fallo sovrapporre alla freccia in modo che venga cliccato anziché sulla freccia.

qualche esempio di codice per ottenere il pulsante per sovrapporre il menù a tendina:

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

Il gestore eventi Click ha la necessità di mostrare una finestra di dialogo che contiene un 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); 
     } 
    } 

Con CalendarForm un modulo che aggiungi che è senza bordi e contiene solo un 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 Fantastico! Legge come un SOX (Visual KB?), Se funziona quando lo provo il lunedì, nessuna parola può esprimere la mia gratitudine. Livello –

+1

di eccezionale superamento. Bello Hans –

2

speculazione:
L'errore si verifica perché la superficie del DateTimePicker non viene eseguito il rendering fino a dopo il messaggio viene inviato click.

Passi successivi per rispondere:
Se disponibile, provare a provare con alcuni controlli di selezione data ora di terze parti. Mi rendo conto che questa non è una risposta completa dato che non so ancora se sarà risolvere il problema.

Altra risposta possibile: Ridimensionare il blocco attività per adattarlo al controllo. Questo risolve il bug, ma sembra un po 'strano dal punto di vista dell'utente.

Problemi correlati