문제

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top