OpenFileDialog/SaveFileDialog의 시작 위치 설정
-
12-09-2019 - |
문제
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
}
}
다른 팁
확인해 보세요 이 기사 코드프로젝트에서.발췌:
편리한 .NET NativeWindow가 그림에 들어오는 경우, NativeWindow는 관련 핸들이 보낸 메시지를 처리하는 창 래퍼입니다.그것은 NativeWindow를 생성하고 OpenFileWindow 핸들을 연관시킵니다.이 시점부터 OpenFileWindow로 전송 된 모든 메시지는 대신 NativeWindow에서 우리 자신의 WNDPROC 메소드로 리디렉션되며, 취소, 수정 또는 통과 할 수 있습니다.
WNDPROC에서 우리는 메시지 WM_WINDOWPOSCHANGING을 처리합니다.열기 대화 상자가 열리면 사용자가 설정 한 시작 가로에 따라 원래 수평 또는 수직 크기를 변경합니다.창의 크기가 증가합니다.이것은 컨트롤이 열릴 때만 한 번만 발생합니다.
또한 메시지 WM_SHOWWINDOW를 처리합니다.여기서 원래 OpenFileDialog 내부의 모든 컨트롤이 생성되며 Open 파일 대화 상자에 대한 제어를 추가 할 것입니다.이것은 Win32 API SetParent를 호출하여 수행됩니다.이 API를 사용하면 부모 창을 변경할 수 있습니다.그런 다음 기본적으로 STARTLOCTION 속성의 값에 따라 설정된 위치의 원래 OpenFiledialog에 컨트롤을 첨부하는 것입니다.
그것의 장점은 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의 답변에 매우 감사드립니다.몇 가지 "문제"가 더 있습니다.OpenFileDialog1.ShowDialog(PositionForm)을 호출할 때 PositionForm의 핸들을 전달해야 합니다. 그렇지 않으면 BobB의 기술이 모든 경우에 신뢰할 수 없습니다.또한 이제 W8.1은 SkyDrive가 포함된 새로운 fileopen 컨트롤을 시작하므로 W8.1 fileopen 컨트롤의 Documents 폴더 위치가 잘못되었습니다.그래서 저는 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