Установка начальной позиции для OpenFileDialog / SaveFileDialog - PullRequest
22 голосов
/ 10 августа 2009

Для любого настраиваемого диалогового окна (формы) в приложении WinForm я могу установить его размер и положение, прежде чем отобразить его с помощью:

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

Это особенно важно при работе с несколькими мониторами. Без такого кода при открытии диалога из приложения, которое вы перетащили на второй монитор, диалоговое окно появляется на основном мониторе. Это представляет плохой пользовательский опыт.

Мне интересно, есть ли какие-нибудь хуки для установки позиции для стандартных .NET OpenFileDialog и SaveFileDialog (у которых нет свойства StartPosition).

Ответы [ 7 ]

4 голосов
/ 10 августа 2009

Проверьте эту статью на CodeProject. Выдержки:

Вот когда пригодится .NET NativeWindow входит в картину, NativeWindow - это оболочка окна, где он обрабатывает сообщения, отправленные ручка связана с ним. Это создает NativeWindow и связывает OpenFileWindow дескриптор к нему. Из этого точка, каждое сообщение отправлено OpenFileWindow будет перенаправлено на наш собственный метод WndProc в Вместо NativeWindow, и мы можем отменить, изменить или позволить им пройти через.

В нашем WndProc мы обрабатываем сообщение WM_WINDOWPOSCHANGING. Если открыт диалог открывается, тогда мы изменим исходный горизонтальный или вертикальный размер в зависимости от StartLocation устанавливается пользователем. Это увеличит размер окна, которое будет создано. это происходит только один раз, когда контроль открыт.

Также мы обработаем сообщение WM_SHOWWINDOW. Здесь все элементы управления внутри оригинального OpenFileDialog есть создано, и мы собираемся добавить наш контроль над диалогом открытия файла. Это делается путем вызова Win32 API SetParent. Этот API позволяет вам изменить родительское окно. Тогда в основном что он делает, это присоединяет наш контроль к оригинальному OpenFileDialog в расположение, которое он установил, в зависимости от значение свойства StartLocation.

Преимущество в том, что мы все еще иметь полный контроль над элементы управления прикреплены к Окно OpenFileDialog. Это означает, что мы может получать события, вызывать методы и делать то, что мы хотим с этими управление.

4 голосов
/ 10 августа 2009

Я подозреваю, что лучшее, что вы можете сделать, это убедиться, что вы используете перегрузку ShowDialog, которая принимает IWin32Window для использования в качестве родителя. Это может помочь ему выбрать подходящее место; чаще всего:

using(var dlg = new OpenFileDialog()) {
    .... setup
    if(dlg.ShowDialog(this) == DialogResult.OK) {
        .... use
    }
}
2 голосов
/ 16 ноября 2016

У меня была эта проблема большую часть вчерашнего дня. Ответ Боба помог мне больше всего (Спасибо, Боб).

Вы можете даже пойти настолько далеко, чтобы создать закрытый метод, который создает окно и закрывает его перед вызовом метода dialog.ShowDialog(), и он все равно будет центрировать 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;
}

Затем вызовите его в любом методе перед 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;
}
1 голос
/ 30 июня 2013

OpenFileDialog и SaveFileDialog располагаются в верхнем левом углу клиентская область последнего отображаемого окна. Поэтому просто создайте новое невидимое окно, расположенное там, где вы хотите, чтобы диалоговое окно отображалось, прежде чем создавать и показывать это диалоговое окно.

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();
1 голос
/ 08 мая 2012

Вот как я это сделал:

Точка, в которой я хочу отобразить OpenFileDialog:

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

DialogResult dr = ofd.ShowDialog();

Код репозиции:

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

Я запускаю тему, которая ищет окно с заголовком «Открыть». (Обычно встречается за 3 итерации или 15 миллисекунд.) Затем я устанавливаю его положение с помощью полученного дескриптора. (См. Документацию SetWindowPos для параметров позиции / размера.)

запутано.

0 голосов
/ 23 января 2014

Очень благодарен за ответ BobB на этот.Есть еще несколько "ошибок".Вы должны передать дескриптор PositionForm при вызове OpenFileDialog1.ShowDialog (PositionForm), в противном случае методика BobB не надежна во всех случаях.Кроме того, теперь, когда W8.1 запускает новый элемент управления открытием файла со SkyDrive, расположение папки «Документы» в элементе управления открытием файла W8.1 теперь не работает.Поэтому я открываю fileopen, чтобы использовать старый элемент управления W7, установив ShowHelp = True.

Вот код VB.NET, который я в итоге использовал, мой вклад в сообщество, если он поможет.

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
0 голосов
/ 10 августа 2009

Существует довольно старый пример одного подхода в MSDN.

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

Включает весь код, необходимый для реализации вашего собственного класса OpenFileDialog, который обеспечивает расширяемость.

...