设置 OpenFileDialog/SaveFileDialog 的起始位置

发布于 2024-08-02 01:45:22 字数 348 浏览 9 评论 0原文

对于 WinForm 应用程序中的任何自定义对话框(表单),我可以在显示它之前设置其大小和位置:

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

这在处理多个监视器时尤其重要。 如果没有此类代码,当您从已拖动到第二个显示器的应用程序中打开对话框时,该对话框将显示在主显示器上。 这呈现出较差的用户体验。

我想知道是否有任何钩子可以设置标准 .NET OpenFileDialog 和 SaveFileDialog(没有 StartPosition 属性)的位置。

For any custom dialog (form) in a WinForm application I can set its size and position before I display it with:

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

This is particularly important when dealing with multiple monitors. Without such code, when you open a dialog from an application that you have dragged to a second monitor, the dialog appears on the primary monitor. This presents a poor user experience.

I am wondering if there are any hooks to set the position for the standard .NET OpenFileDialog and SaveFileDialog (which do not have a StartPosition property).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

与君绝 2024-08-09 01:45:22

我怀疑您能做的最好的事情就是确保使用 重载 ShowDialog 接受 IWin32Window 用作父级。 这可能帮助它选择合适的位置; 最常见的:

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

I suspect that the best you can do is make sure you use the overload of ShowDialog that accepts an IWin32Window to use as the parent. This might help it choose an appropriate location; most commonly:

using(var dlg = new OpenFileDialog()) {
    .... setup
    if(dlg.ShowDialog(this) == DialogResult.OK) {
        .... use
    }
}
雨轻弹 2024-08-09 01:45:22

请查看 CodeProject 上的这篇文章。 摘抄:

这是方便的 .NET
NativeWindow 出现了,一个
NativeWindow 是一个窗口包装器,其中
它处理由
与其关联的句柄。 它创建了一个
NativeWindow 并关联
OpenFileWindow 的句柄。 由此
点,发送到的每条消息
OpenFileWindow 将被重定向到
我们自己的 WndProc 方法
相反,我们可以使用 NativeWindow
取消、修改或让其通过
通过。

在我们的WndProc中,我们处理消息
WM_WINDOWPOSCHANGING。 如果打开
对话框正在打开,然后我们将进行更改
原来的水平或垂直
大小取决于 StartLocation
由用户设置。 它将增加
要创建的窗口的大小。 这
控制时仅发生一次
打开。

此外,我们将处理该消息
WM_SHOWWWINDOW。 在这里,所有控件
原来的 OpenFileDialog 里面有
创建,我们将追加
我们对打开文件对话框的控制。
这是通过调用 Win32 API 来完成的
设置父级。 这个API可以让你改变
父窗口。 那么,基本上
它所做的就是附加我们的控制
到原来的OpenFileDialog
它设置的位置,取决于
StartLocation 属性的值。

它的好处是我们仍然
完全控制
附加到的控件
打开文件对话框窗口。 这意味着我们
可以接收事件、调用方法,以及
对它们做任何我们想做的事
控制。

Check out this article on CodeProject. Excerpt:

Here is when the handy .NET
NativeWindow comes into the picture, a
NativeWindow is a window wrapper where
it processes the messages sent by the
handle associated to it. It creates a
NativeWindow and associates the
OpenFileWindow handle to it. From this
point, every message sent to
OpenFileWindow will be redirected to
our own WndProc method in the
NativeWindow instead, and we can
cancel, modify, or let them pass
through.

In our WndProc, we process the message
WM_WINDOWPOSCHANGING. If the open
dialog is opening, then we will change
the original horizontal or vertical
size depending of the StartLocation
set by the user. It will increment the
size of the window to be created. This
happens only once when the control is
opened.

Also, we will process the message
WM_SHOWWINDOW. Here, all controls
inside the original OpenFileDialog are
created, and we are going to append
our control to the open file dialog.
This is done by calling a Win32 API
SetParent. This API lets you change
the parent window. Then, basically
what it does is attach our control
to the original OpenFileDialog in the
location it set, depending on the
value of the StartLocation property.

The advantage of it is that we still
have complete control over the
controls attached to the
OpenFileDialog window. This means we
can receive events, call methods, and
do whatever we want with those
controls.

寄居者 2024-08-09 01:45:22

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 and SaveFileDialog position themselves in the upper-left corner of
the client area of the most recently displayed window. So just create a new invisible window positioned where you want the the dialog to appear before creating and showing that dialog.

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();
迷鸟归林 2024-08-09 01:45:22

我昨天大部分时间都遇到这个问题。 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;
}

I had this problem for most of yesterday. BobB's answer was the one that helped me out the most (Thanks BobB).

You can even go as far as to make a private method that creates a window and closes it before the dialog.ShowDialog() method call and it will still centre the 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;
}

Then call it in any method before the ShowDialog() method.

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;
}
梦年海沫深 2024-08-09 01:45:22

我是这样做的:

我想要显示 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);
}

我启动一个线程来查找标题为“Open”的窗口。 (通常在 3 次迭代或 15 毫秒内发现。)然后我使用获得的句柄设置其位置。 (有关位置/大小参数,请参阅 SetWindowPos 文档。)

Kludgy。

Here's how I did it:

The point where I want to display the OpenFileDialog:

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

DialogResult dr = ofd.ShowDialog();

The repositioning code:

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

I start a thread that looks for a window with the "Open" title. (Typically found in 3 iterations or 15 milliseconds.) Then I set its position with the obtained handle. (See SetWindowPos documentation for the position/size parameters.)

Kludgy.

别把无礼当个性 2024-08-09 01:45:22

MSDN 上有一个相当古老的方法示例。

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

它包含实现您自己的允许扩展性的 OpenFileDialog 类所需的所有代码。

There is quite an old example of one approach on MSDN.

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

It includes all the code needed to implement your own OpenFileDialog class that allows extensibility.

酷遇一生 2024-08-09 01:45:22

非常感谢BobB对此的回复。 还有一些“陷阱”。 调用 OpenFileDialog1.ShowDialog(PositionForm) 时必须传递 PositionForm 的句柄,否则 BobB 的技术并非在所有情况下都可靠。 另外,现在 W8.1 启动了一个新的文件打开控件,其中包含 SkyDrive,W8.1 文件打开控件中的文档文件夹位置现在已被固定。 因此,我通过设置 ShowHelp = True 来使用旧的 W7 控件来打开 fileopen。

这是我最终使用的 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

Very grateful for BobB's reply on this one. There are a few more "gotchas". You have to pass the handle of PositionForm when calling OpenFileDialog1.ShowDialog(PositionForm) otherwise BobB's technique is not reliable in all cases. Also, now that W8.1 launches a new fileopen control with SkyDrive in it, the Documents folder location in the W8.1 fileopen control is now screwed. So I frig fileopen to use the old W7 control by setting ShowHelp = True.

Here is the VB.NET code I ended up using, my contribution to the community in case it helps.

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
爱已欠费 2024-08-09 01:45:22

以 Rob Sherrit 在 2014 年 1 月 22 日的回复为灵感,我创建了一个新模块,并将其命名为 CKRFileDialog(随你所想),其中包含以下代码:

Public Function Show(fd As Object, CoveredForm As Form, Optional bShowHelp As Boolean = False) As DialogResult

    Dim oDR As DialogResult

    'The .Net FileDialogs open in the last Form that was created. 
    'To ensure they appear in the area of the current Form, we create a new HIDDEN PositionForm and then 
    'delete it afterwards.

    Dim PositionForm As New Form With {
      .StartPosition = FormStartPosition.Manual,
      .Left = CoveredForm.Left + CInt(CoveredForm.Width / 8),  'adjust as required
      .Top = CoveredForm.Top + CInt(CoveredForm.Height / 8),   'adjust as required
      .Width = 0,
      .Height = 0,
      .FormBorderStyle = Windows.Forms.FormBorderStyle.None,
      .Visible = False
    }
    PositionForm.Show()

    'If you use SkyDrive you need to ensure that "bShowHelp" is set to True in the passed parameters.
    'This is a workaround for a problem on W8.1 machines with SkyDrive installed.
    'Setting it to "true" causes the "old" W7 control to be used which avoids a pointing to SkyDrive error.
    'If you do not use SkyDrive then simply do not pass the last parameter (defaults to "False")
    fd.ShowHelp = bShowHelp

    'store whether the form calling this routine is set as "topmost"
    Dim oldTopMost As Integer = CoveredForm.TopMost
    'set the calling form's topmost setting to "False" (else the dialogue will be "buried"
    CoveredForm.TopMost = False

    oDR = fd.ShowDialog(PositionForm)

    'set the "topmost" setting of the calling form back to what it was.
    CoveredForm.TopMost = oldTopMost
    PositionForm.Close()
    PositionForm.Dispose()
    Return oDR

End Function

然后,我在各个模块中调用此代码,如下所示:

如果执行“ FileOpen”确保有一个 FileOpenDialog 组件添加到您的表单或代码中,并根据需要调整该组件的属性
(例如 InitDirectory、Multiselect 等)

使用 FileSaveDialog 组件时执行相同的操作(可能适用于 FileOpenDialog 组件的不同属性)。

要“显示”对话框组件,请使用一行代码,如下所示,传递两个参数,第一个参数是您正在使用的文件对话框(“打开”或“保存”),第二个参数是您希望在其上覆盖对话框的表单。

CKRFileDialog.Show(saveFileDialog1, CoveredForm)
或者
CKRFileDialog.Show(openFileDialog1, CoveredForm)

请记住,如果您使用 SkyDrive,则必须传递“True”作为第三个参数:

CKRFileDialog.Show(saveFileDialog1, CoveredForm, True)
或者
CKRFileDialog.Show(openFileDialog1, CoveredForm, True)

我将对话框的“偏移”设置为表单上横向和纵向的 1/8
“CoveredForm”,但您可以将其设置回 1/2(如 Rob Sherret 的代码中所示)或您希望的任何值。

这似乎是最简单的方法

谢谢罗布! :-)

Using Rob Sherrit's response on Jan 22 '14 as inspiration, I created a new module and called it CKRFileDialog (call it what you want) which contains the following code:

Public Function Show(fd As Object, CoveredForm As Form, Optional bShowHelp As Boolean = False) As DialogResult

    Dim oDR As DialogResult

    'The .Net FileDialogs open in the last Form that was created. 
    'To ensure they appear in the area of the current Form, we create a new HIDDEN PositionForm and then 
    'delete it afterwards.

    Dim PositionForm As New Form With {
      .StartPosition = FormStartPosition.Manual,
      .Left = CoveredForm.Left + CInt(CoveredForm.Width / 8),  'adjust as required
      .Top = CoveredForm.Top + CInt(CoveredForm.Height / 8),   'adjust as required
      .Width = 0,
      .Height = 0,
      .FormBorderStyle = Windows.Forms.FormBorderStyle.None,
      .Visible = False
    }
    PositionForm.Show()

    'If you use SkyDrive you need to ensure that "bShowHelp" is set to True in the passed parameters.
    'This is a workaround for a problem on W8.1 machines with SkyDrive installed.
    'Setting it to "true" causes the "old" W7 control to be used which avoids a pointing to SkyDrive error.
    'If you do not use SkyDrive then simply do not pass the last parameter (defaults to "False")
    fd.ShowHelp = bShowHelp

    'store whether the form calling this routine is set as "topmost"
    Dim oldTopMost As Integer = CoveredForm.TopMost
    'set the calling form's topmost setting to "False" (else the dialogue will be "buried"
    CoveredForm.TopMost = False

    oDR = fd.ShowDialog(PositionForm)

    'set the "topmost" setting of the calling form back to what it was.
    CoveredForm.TopMost = oldTopMost
    PositionForm.Close()
    PositionForm.Dispose()
    Return oDR

End Function

I then call this code in my various modules as follows:

If performing a "FileOpen" ensure that there is a FileOpenDialog component added to your form or code and adjust the properties of the component if you wish
(e.g. InitDirectory,Multiselect,etc.)

Do the same when using FileSaveDialog components (Different properties to the FileOpenDialog component may apply).

To "show" the dialog component use a line of code as follows, passing two parameters, the first the FileDialog you are using ("Open" or "Save") and the second parameter the Form upon which you wish to overlay the dialogue.

CKRFileDialog.Show(saveFileDialog1, CoveredForm)
or
CKRFileDialog.Show(openFileDialog1, CoveredForm)

Remember, if you are using SkyDrive you must pass "True" as a third parameter:

CKRFileDialog.Show(saveFileDialog1, CoveredForm, True)
or
CKRFileDialog.Show(openFileDialog1, CoveredForm, True)

I set the "offset" of the dialogue to be 1/8 the way across and down on the form
"CoveredForm", but you can set that back to 1/2 (as in Rob Sherret's code) or whatever value you wish.

This seemed the easiest approach

Thanks Rob! :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文