Вопрос

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

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

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

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

Это было полезно?

Решение

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

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

Другие советы

Проверьте эта статья в CodeProject.Отрывок:

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

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

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

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

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

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

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();

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

Момент, когда я хочу отобразить 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.)

Клуджи.

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

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

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

Очень благодарен 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top