Pergunta

Para qualquer diálogo personalizada (forma) em um aplicativo WinForm posso definir seu tamanho e posição antes de exibi-lo com:

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

Isto é particularmente importante quando se lida com vários monitores. Sem esse código, quando você abrir uma janela de um aplicativo que você tenha arrastado para um segundo monitor, aparece de diálogo no monitor primário. Isto apresenta uma má experiência do usuário.

Eu estou querendo saber se existem ganchos para definir a posição para o padrão .NET OpenFileDialog e SaveFileDialog (que não têm uma propriedade StartPosition).

Foi útil?

Solução

Eu suspeito que o melhor que você pode fazer é certificar-se de que você use o sobrecarga de ShowDialog que aceita um IWin32Window para usar como o pai. Este força ajuda que escolher um local apropriado; mais comumente:

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

Outras dicas

Confira este artigo em CodeProject. Trecho:

Aqui é quando o .NET útil NativeWindow entra em cena, um NativeWindow é um wrapper janela onde ele processa as mensagens enviadas pelo identificador associado a ele. Ele cria uma NativeWindow e associa o OpenFileWindow lidar com ele. disto ponto, cada mensagem enviada para OpenFileWindow será redirecionado para o nosso próprio método WndProc na NativeWindow vez, e nós podemos cancelar, modificar ou deixá-los passar through.

No nosso WndProc, processamos a mensagem WM_WINDOWPOSCHANGING. Se a céu aberto diálogo está abrindo, então vamos mudar a horizontal original ou vertical tamanho dependendo do StartLocation definido pelo usuário. Ele vai incrementar o tamanho da janela a ser criado. Esta acontece apenas uma vez quando o controle é aberto.

Além disso, vamos processar a mensagem WM_SHOWWINDOW. Aqui, todos os controles dentro do original são OpenFileDialog criado, e nós estamos indo para anexar nosso controle para o diálogo de arquivo aberto. Isso é feito chamando a API Win32 SetParent. Esta API permite que você altere janela pai. Então, basicamente, o que ele faz é anexar nosso controle ao OpenFileDialog original no localização que definir, dependendo da valor da propriedade StartLocation.

A vantagem disso é que ainda tem controle total sobre o controlos ligados ao janela OpenFileDialog. Isso significa que pode receber eventos, métodos de chamada e fazer o que quisermos com os controles.

Eu tive esse problema para a maioria de ontem. A resposta de Bobb foi o que me ajudou a mais (Obrigado Bobb).

Você pode até mesmo ir tão longe como fazer um método particular que cria uma janela e fecha-lo antes da chamada de método dialog.ShowDialog() e ainda vai centrar a 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;
}

Em seguida, chamá-lo em qualquer método antes que o 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 e SaveFileDialog se posicionam no canto superior esquerdo da área de cliente da janela exibido mais recentemente. Então, basta criar uma nova janela invisível posicionado onde deseja que a caixa de diálogo para aparecer antes de criar e mostrar que 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();

Aqui está como eu fiz isso:

O ponto onde eu quero mostrar o OpenFileDialog:

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

DialogResult dr = ofd.ShowDialog();

O código de reposicionamento:

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

Eu iniciar uma discussão que procura por uma janela com o título "Open". (Encontrado tipicamente em 3 iterações ou 15 milissegundos.) Em seguida, definir a sua posição com o identificador obtido. (Veja SetWindowPos documentação para os parâmetros de posição / tamanho).

kludgy.

Não é muito um velho exemplo de uma abordagem no MSDN.

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

Ele inclui todo o código necessário para implementar sua própria classe OpenFileDialog que permite extensibilidade.

Muito grato pela resposta de Bobb em um presente. Há mais algumas "pegadinhas". Você tem que passar o identificador de PositionForm ao chamar OpenFileDialog1.ShowDialog (PositionForm), caso contrário a técnica de Bobb não é confiável em todos os casos. Além disso, agora que os lançamentos W8.1 um novo controle FileOpen com SkyDrive nele, os documentos da pasta local no controle W8.1 FileOpen está ferrado. Então eu frig FileOpen usar o controle antigo W7, definindo ShowHelp = True.

Aqui está o código VB.NET acabei usando, minha contribuição para a comunidade no caso de ajuda.

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top