Pregunta

Para cualquier diálogo personalizado (forma) en una aplicación WinForm puedo fijar su tamaño y posición antes de que exhibo con:

form.StartPosition = FormStartPosition.Manual;
form.DesktopBounds = MyWindowPosition;

Esto es particularmente importante cuando se trata de múltiples monitores. Sin ese código, cuando se abre un cuadro de diálogo desde una aplicación que ha arrastrado a un segundo monitor, aparece el cuadro de diálogo en el monitor principal. Esto presenta una experiencia de usuario pobre.

Me gustaría saber si hay algún ganchos para fijar la posición de la norma .NET OpenFileDialog y SaveFileDialog (que no tienen una propiedad StartPosition).

¿Fue útil?

Solución

Sospecho que lo mejor que puede hacer es asegurarse de que utiliza la sobrecarga de ShowDialog que acepta un IWin32Window utilizar como padre. Este podría ayudarla a elegir un lugar apropiado; más comúnmente:

using(var dlg = new OpenFileDialog()) {
    .... setup
    if(dlg.ShowDialog(this) == DialogResult.OK) {
        .... use
    }
}

Otros consejos

este artículo en CodeProject. Extracto:

  

Aquí es cuando la mano .NET   NativeWindow entra en la imagen, una   NativeWindow es un envoltorio ventana donde   que procesa los mensajes enviados por el   identificador asociado a la misma. Se crea una   NativeWindow y asocia las   OpenFileWindow manejar a ella. De esto   punto, cada mensaje enviado a   OpenFileWindow será redirigido a   nuestro propio método WndProc en el   NativeWindow lugar, y podemos   cancelar, modificar, o dejarlos pasar   a través.

     

En nuestro WndProc, se procesa el mensaje   WM_WINDOWPOSCHANGING. Si la apertura   de diálogo se abre, entonces cambiaremos   la horizontal original o vertical   tamaño dependiendo de la StartLocation   establecido por el usuario. Se incrementará el   tamaño de la ventana que se creará. Esta   ocurre sólo una vez cuando el control está   abierto.

     

Además, vamos a procesar el mensaje   WM_SHOWWINDOW. En este caso, todos los controles   dentro del OpenFileDialog originales se   creamos, y vamos a añadir   nuestro control del diálogo de archivos abiertos.   Esto se hace llamando a una API de Win32   SetParent. Esta API permite cambiar   la ventana padre. Entonces, básicamente   lo que hace es conectar nuestro control   OpenFileDialog a la original en el   ubicación se establece en función de la   valor de la propiedad StartLocation.

     

La ventaja de ello es que todavía   tener un control completo sobre el   controles unido a la   OpenFileDialog ventana. Esto significa que   puede recibir eventos, llamar a los métodos y   hacer lo que queramos con las   controles.

he tenido este problema durante la mayor parte del día de ayer. La respuesta de Bobb fue la que me ayudó a cabo la mayor parte (Gracias Bobb).

Usted puede incluso ir tan lejos como para hacer un método privado que crea una ventana y se cierra antes de la llamada al método dialog.ShowDialog() y todavía centrará el OpenFileDialog.

private void openFileDialogWindow()
{
    Window openFileDialogWindow = new Window();
    openFileDialogWindow.Left = this.Left;
    openFileDialogWindow.Top = this.Top;
    openFileDialogWindow.Width = 0;
    openFileDialogWindow.Height = 0;
    openFileDialogWindow.WindowStyle = WindowStyle.None;
    openFileDialogWindow.ResizeMode = ResizeMode.NoResize;
    openFileDialogWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;

    openFileDialogWindow.Show();
    openFileDialogWindow.Close();

    openFileDialogWindow = null;
}

A continuación, llamar en cualquier método antes del método ShowDialog().

public string SelectWebFolder()
{
    string WebFoldersDestPath = null;

    CommonOpenFileDialog filePickerDialog = new CommonOpenFileDialog();
    // OpenFileDialog Parameters..

    openFileDialogWindow();

    if (filePickerDialog.ShowDialog() == CommonFileDialogResult.Ok)
    {
        WebFoldersDestPath = filePickerDialog.FileName + "\\";
    }

    filePickerDialog = null;

    return WebFoldersDestPath;
}

OpenFileDialog y SaveFileDialog posicionarse en la esquina superior izquierda de el área de cliente de la ventana que se muestra más recientemente. Así que simplemente crear una nueva ventana invisible colocado donde desea que el cuadro de diálogo que aparezca antes de crear y mostrar ese diálogo.

Window dialogPositioningWindow = new Window();
dialogPositioningWindow.Left = MainWindow.Left + <left position within main window>;
dialogPositioningWindow.Top  = MainWindow.Top  + <top  position within main window>;
dialogPositioningWindow.Width = 0; 
dialogPositioningWindow.Height = 0; 
dialogPositioningWindow.WindowStyle = WindowStyle.None;
dialogPositioningWindow.ResizeMode = ResizeMode.NoResize;
dialogPositioningWindow.Show();// OpenFileDialog is positioned in the upper-left corner
                               // of the last shown window (dialogPositioningWindow)
Microsoft.Win32.OpenFileDialog dialog = new Microsoft.Win32.OpenFileDialog();
...
if ((bool)dialog.ShowDialog()){
   ...
}
dialogPositioningWindow.Close();

Así es como lo hice:

El punto en el que desea mostrar el OpenFileDialog:

Thread posThread = new Thread(positionOpenDialog);
posThread.Start();

DialogResult dr = ofd.ShowDialog();

El código de reposicionamiento:

[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);


/// <summary>
/// Find the OpenFileDialog window when it appears, and position it so
/// that we can see both dialogs at once.  There is no easier way to
/// do this (&^%$! Microsoft!).
/// </summary>
private void positionOpenDialog ()
{
    int count = 0;
    IntPtr zero = (IntPtr)0;
    const int SWP_NOSIZE = 0x0001;
    IntPtr wind;

    while ((wind = FindWindowByCaption(zero, "Open")) == (IntPtr)0)
        if (++count > 100)
            return;             // Find window failed.
        else
            Thread.Sleep(5);

    SetWindowPos(wind, 0, Right, Top, 0, 0, SWP_NOSIZE);
}

inicio un hilo que busca una ventana con el título "abierto". (Se encuentran típicamente en 3 iteraciones o 15 milisegundos.) Entonces me puse su posición con el mango obtenido. (Consulte la documentación SetWindowPos para los parámetros de posición / tamaño.)

kludgy.

Hay bastante un viejo ejemplo de un enfoque en MSDN.

http://msdn.microsoft.com/en-us/library /ms996463.aspx

Incluye todo el código necesario para implementar su propia clase OpenFileDialog que permite la extensibilidad.

Muy agradecido por la respuesta de Bobb en este caso. Hay algunas "trampas" más. Usted tiene que pasar el mango de PositionForm al llamar OpenFileDialog1.ShowDialog (PositionForm) de lo contrario la técnica de Bobb no es fiable en todos los casos. Además, ahora que W8.1 lanza un nuevo control FileOpen con SkyDrive en ella, la ubicación de la carpeta Documentos en el control W8.1 FileOpen está atornillado. Así que Frig FILEOPEN utilizar el viejo sistema de control mediante el establecimiento de W7 ShowHelp = True.

Este es el código VB.NET que terminé usando, mi contribución a la comunidad en caso de que ayuda.

Private Function Get_FileName() As String

    ' Gets an Input File Name from the user, works with multi-monitors

    Dim OpenFileDialog1 As New OpenFileDialog
    Dim PositionForm As New Form
    Dim MyInputFile As String

    ' The FileDialog() opens in the last Form that was created.  It's buggy!  To ensure it appears in the
    ' area of the current Form, we create a new hidden PositionForm and then delete it afterwards.

    PositionForm.StartPosition = FormStartPosition.Manual
    PositionForm.Left = Me.Left + CInt(Me.Width / 2)
    PositionForm.Top = Me.Top + CInt(Me.Height / 2)
    PositionForm.Width = 0
    PositionForm.Height = 0
    PositionForm.FormBorderStyle = Forms.FormBorderStyle.None
    PositionForm.Visible = False
    PositionForm.Show()

    ' Added the statement "ShowHelp = True" to workaround a problem on W8.1 machines with SkyDrive installed.
    ' It causes the "old" W7 control to be used that does not point to SkyDrive in error.

    OpenFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
    OpenFileDialog1.Filter = "Excel files (*.xls*)|*.xls*|CSV Files (*.csv)|*.csv"
    OpenFileDialog1.FilterIndex = 1
    OpenFileDialog1.RestoreDirectory = True
    OpenFileDialog1.AutoUpgradeEnabled = False
    OpenFileDialog1.ShowHelp = True
    OpenFileDialog1.FileName = ""
    OpenFileDialog1.SupportMultiDottedExtensions = False
    OpenFileDialog1.Title = "Select an Excel or .csv file containing patent data or list of Publication Numbers for your project."

    If OpenFileDialog1.ShowDialog(PositionForm) <> System.Windows.Forms.DialogResult.OK Then
        Console.WriteLine("No file was selected. Please try again!")
        PositionForm.Close()
        PositionForm.Dispose()
        OpenFileDialog1.Dispose()
        Return ""
    End If
    PositionForm.Close()
    PositionForm.Dispose()

    MyInputFile = OpenFileDialog1.FileName
    OpenFileDialog1.Dispose()
    Return MyInputFile

End Function
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top