2012-05-10 28 views
9

guardado El problema con Microsoft aquí - la Repro está disponible para su descarga: https://connect.microsoft.com/VisualStudio/feedback/details/741454/value-change-event-doesnt-fire-for-datetimepicker-controls-used-in-vsto-add-insERROR: canto elige fechas en un DatePicker que caen fuera de un flotante VSTO Add-In

Si se pone un DateTimePicker en un VSTO Excel flotante Añadir -En y la posición, así que cuando el calendario se despliega, se encuentra fuera del borde del complemento, ver aquí:

enter image description here

la elección de cualquiera de las fechas en círculos en los trabajos verdes como se esperaba, pero cuando Al hacer clic en cualquier fecha marcada con un círculo en rojo, simplemente cierra el menú desplegable del calendario y no establece la fecha.

¿Alguien sabe cómo puedo solucionar esto?

EDITAR

Este usuario también lo ha experimentado el problema usando WPF: VSTO WPF ContextMenu.MenuItem Click outside a TaskPane not raised

enter image description here

La respuesta a esta pregunta muestra se comunicó el problema de conectar un tiempo atrás, pero todavía no hay solución con 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 de las soluciones consiste en utilizar el DispatcherFrame para bombear mensajes y suscribirse a GotFocusEvent y LostFocusEvent para el menú. 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 pero esto es todo el código WPF para el menú no es una solución para Winform DateTimePicker.

Repro de Microsoft Connect:

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

menú Archivo> Agregar> Nuevo proyecto> Biblioteca de clases> llamado TaskPane

Luego, en el Proyecto TaskPane crear un control de usuario llamado 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; } 
    } 

} 

A continuación, cree un control de usuario con un DateTimePicker, asegúrese de que el control de calendario se encuentra hacia la parte inferior derecha del control de usuario

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

F5 y haga clic en el control de calendario, ahora tratar de seleccionar una fecha que está fuera del área del área de trabajo. Sin eventos de cambio de valor, se comporta como un clic fuera del calendario.

Nota: Probé una lista desplegable que se cae fuera del control pero sus eventos ¡HACEN FUEGO!

Respuesta

7

"Floating" es la clave del problema aquí. Lo que nunca es un problema es que confía en la bomba de mensajes en Excel para enviar mensajes de Windows, los mensajes que hacen que estos controles respondan a la entrada. Esto funciona tanto en WPF como en Winforms, tienen su propio bucle de envío que filtra los mensajes antes de que se envíen a la ventana. Las cosas clave que salen mal cuando no se utiliza su despachador respectivo son cosas como tabulación y atajos de teclado.

Y luego, este tipo de problema sería inducido por Excel haciendo su propio filtrado antes de enviar mensajes. Supongo que en una característica anti-malware, Microsoft siempre está preocupado por los programas que juegan con las aplicaciones de Office.

La solución de Winforms es la misma que la solución de WPF; debe bombear su propio bucle de mensajes. Eso requiere un poco de cirugía, DateTimePicker no va a cooperar ya que no permite que su evento DropDown se cancele y se levanta después de el calendario ya se muestra. La solución alternativa es tonta pero efectiva, agregue un botón a su formulario que se parece a la flecha desplegable en el DTP y haga que se superponga a la flecha para que haga clic en lugar de la flecha.

un código de ejemplo para obtener el botón para solapar la flecha de la derecha:

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

El controlador de eventos Click tiene que mostrar un cuadro de diálogo que contiene una 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 una forma que agrega que no tiene bordes y contiene solo un MesCalendario:

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! Lee como SOX (KB visual?), Si funciona cuando lo pruebo el lunes, no hay palabras que puedan expresar mi gratitud. –

+1

nivel de increíble excedido. un buen Hans –

2

speculation:
El error se produce porque la superficie del datetimepicker no se representa hasta que se envía el mensaje de clic.

Próximos pasos para responder:
Si está disponible, pruebe con algunos controles de selector de fecha y hora de terceros. Me doy cuenta de que esta no es una respuesta completa, ya que aún no sé si solucionará su problema.

Otra respuesta posible: Cambie el tamaño del panel de tareas para que se ajuste al control. Esto resolverá el error, pero se verá un poco extraño desde el punto de vista del usuario.

Cuestiones relacionadas