Подтвердить что ты не робот

Установка начальной позиции для OpenFileDialog/SaveFileDialog

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

У меня была эта проблема для большей части вчерашнего дня. Ответ 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;
}

Ответ 5

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

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

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

Ответ 6

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

Точка, где я хочу отображать 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 для параметров позиции/размера.)

запутано.

Ответ 7

Очень благодарен за ответ Бобба на этот вопрос. Есть еще несколько "gotchas". Вы должны передать дескриптор PositionForm при вызове OpenFileDialog1.ShowDialog(PositionForm), иначе техника BobB не будет надежной во всех случаях. Кроме того, теперь, когда W8.1 запускает новый элемент управления Fileopen с помощью SkyDrive, папка "Документы" в элементе управления файлом W8.1 теперь завинчивается. Поэтому я использую старый элемент управления 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 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