对于WinForm应用程序中的任何自定义对话框(窗体),我可以在显示它之前设置其大小和位置:
form.StartPosition = FormStartPosition.Manual;
form.DesktopBounds = MyWindowPosition;
在处理多台显示器时,这一点尤为重要。如果没有此类代码,当您从已拖动到第二个监视器的应用程序打开对话框时,对话框将显示在主监视器上。这会带来糟糕的用户体验。
我想知道是否有任何钩子来设置标准.NET OpenFileDialog和SaveFileDialog(没有StartPosition属性)的位置。
答案 0 :(得分:4)
我怀疑您可以做的最好的事情是确保使用接受IWin32Window
的{{3}}作为父级。 可能帮助它选择合适的位置;最常见的是:
using(var dlg = new OpenFileDialog()) {
.... setup
if(dlg.ShowDialog(this) == DialogResult.OK) {
.... use
}
}
答案 1 :(得分:4)
在CodeProject上查看this article。摘录:
这是方便的.NET NativeWindow进入了画面,a NativeWindow是一个窗口包装器 它处理由...发送的消息 与之相关的句柄。它创造了一个 NativeWindow和关联 OpenFileWindow处理它。由此 点,发送给每条消息 OpenFileWindow将被重定向到 我们自己的WndProc方法 相反,NativeWindow,我们可以 取消,修改或让它们通过 通过
在我们的WndProc中,我们处理消息 WM_WINDOWPOSCHANGING。如果开放 对话框正在打开,然后我们将改变 原始的水平或垂直 大小取决于StartLocation 由用户设置。它会增加 要创建的窗口的大小。这个 控制时只发生一次 打开。
此外,我们将处理该消息 WM_SHOWWINDOW。在这里,所有控件 在原来的OpenFileDialog里面 创建了,我们将要追加 我们对打开文件对话框的控制。 这是通过调用Win32 API完成的 的setparent。此API允许您更改 父窗口。然后,基本上 它的作用是附加我们的控制 到原来的OpenFileDialog中 它设置的位置,取决于 StartLocation属性的值。
它的优点是我们仍然 完全控制了 控制附在 OpenFileDialog窗口。这意味着我们 可以接收事件,呼叫方法和 做任何我们想要的东西 控件。
答案 2 :(得分:2)
我昨天的大部分时间都有这个问题。 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;
}
答案 3 :(得分:1)
我是这样做的:
我想要显示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文档。)
缺憾。
答案 4 :(得分:1)
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();
答案 5 :(得分:0)
在MSDN上有一个很老的例子就是一种方法。
http://msdn.microsoft.com/en-us/library/ms996463.aspx
它包含了实现允许可扩展性的自己的OpenFileDialog类所需的所有代码。
答案 6 :(得分:0)
非常感谢BobB对此的回复。还有一些“陷阱”。调用OpenFileDialog1.ShowDialog(PositionForm)时必须传递PositionForm的句柄,否则BobB的技术在所有情况下都不可靠。此外,现在W8.1启动了一个带有SkyDrive的新文件打开控件,W8.1 fileopen控件中的Documents文件夹位置现在已拧紧。所以我通过设置ShowHelp = True来frig fileopen使用旧的W7控件。
这是我最终使用的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
答案 7 :(得分:0)
以Rob Sherrit在14年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组件不同的属性)。
要“显示”对话框组件,请使用以下代码行,并传递两个参数,第一个是您正在使用的FileDialog(“打开”或“保存”),第二个参数是您希望覆盖的窗体对话。
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的代码)或所需的任何值。
这似乎是最简单的方法
谢谢罗伯! :-)