2009-08-10 30 views
20

Đối với bất kỳ hộp thoại tùy chỉnh (theo mẫu) trong một ứng dụng WinForm tôi có thể thiết lập kích thước và vị trí của nó trước khi tôi hiển thị nó với:Thiết lập vị trí bắt đầu cho OpenFileDialog/SaveFileDialog

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

Điều này đặc biệt quan trọng khi giao dịch với nhiều màn hình. Nếu không có mã như vậy, khi bạn mở một hộp thoại từ một ứng dụng mà bạn đã kéo đến một màn hình thứ hai, hộp thoại xuất hiện trên màn hình chính. Điều này thể hiện trải nghiệm người dùng kém.

Tôi tự hỏi nếu có bất kỳ móc nào để đặt vị trí cho tiêu chuẩn .NET OpenFileDialog và SaveFileDialog (không có thuộc tính StartPosition).

Trả lời

3

Tôi nghi ngờ rằng điều tốt nhất bạn có thể làm là đảm bảo bạn sử dụng số overload of ShowDialog chấp nhận số IWin32Window để sử dụng làm phụ huynh. Điều này có thể giúp chọn vị trí phù hợp; phổ biến nhất:

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

Điều này nghe rất đơn giản, nó phải hoạt động (ít nhất nó phải được kiểm tra)! Than ôi, cả 0-arg và 1-arg ShowDialog thất bại trong cùng một cách trên trường hợp kiểm tra này: 1. Chạy ứng dụng. 2. Gọi OpenFileDialog mới(). ShowDialog (điều này); hộp thoại xuất hiện trên cùng một màn hình như ứng dụng. 3. Đóng hộp thoại. 4. Kéo cửa sổ ứng dụng vào màn hình khác. 5. Gọi OpenFileDialog mới(). ShowDialog (điều này); hộp thoại xuất hiện trên màn hình * gốc *. Mặc dù tôi sử dụng OpenFileDialog mới trong bước 5, vẫn có một cái gì đó liên tục về vị trí ban đầu của ứng dụng chính. –

+1

Tôi (cuối cùng :-) chọn câu trả lời của Marc là tốt nhất vì gần đây tôi đã phát hiện ra nó * áp dụng cho Windows 7. Máy của tôi là WinXP, nơi mà trường hợp thử nghiệm tôi phác thảo ở trên vẫn không thành công. Tôi quyết định thử các diễn đàn của Microsoft với cùng một câu hỏi và được cung cấp một giải pháp hoạt động cho WinXP - xem chủ đề này (http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/dec48489- 0a57-4baa-b401-82266be782e0) cho mã. –

4

Kiểm tra this article trên CodeProject. Trích:

Dưới đây là khi NET tiện dụng NativeWindow đi vào hình ảnh, một NativeWindow là một wrapper cửa sổ nơi nó xử lý các thông điệp được gửi bởi xử lý liên quan đến nó. Nó tạo ra một NativeWindow và kết hợp xử lý OpenFileWindow với nó. Từ điểm này, mọi thư được gửi đến OpenFileWindow sẽ được chuyển hướng đến phương thức WndProc riêng của chúng tôi trong NativeWindow thay vào đó và chúng tôi có thể hủy, sửa đổi hoặc để chúng vượt qua .

Trong WndProc của chúng tôi, chúng tôi xử lý thông báo WM_WINDOWPOSCHANGING. Nếu hộp thoại mở đang mở, thì chúng tôi sẽ thay đổi kích thước ngang ngang hoặc dọc ban đầu tùy thuộc vào StartLocation do người dùng đặt. Nó sẽ tăng kích thước của cửa sổ sẽ được tạo. Điều này xảy ra chỉ một lần khi kiểm soát được mở .

Ngoài ra, chúng tôi sẽ xử lý thông báo WM_SHOWWINDOW. Ở đây, tất cả các điều khiển bên trong OpenFileDialog ban đầu là được tạo và chúng tôi sẽ thêm điều khiển của chúng tôi vào hộp thoại tệp đang mở. Điều này được thực hiện bằng cách gọi một API Win32 SetParent. API này cho phép bạn thay đổi cửa sổ chính. Sau đó, về cơ bản những gì nó làm là đính kèm kiểm soát của chúng tôi vào OpenFileDialog gốc ở vị trí được đặt, tùy thuộc vào giá trị của thuộc tính StartLocation.

Lợi thế của nó là chúng tôi vẫn còn có toàn quyền kiểm soát các điều khiển được đính kèm với cửa sổ OpenFileDialog. Điều này có nghĩa là chúng tôi có thể nhận các sự kiện, phương thức gọi và làm bất cứ điều gì chúng tôi muốn với các điều khiển đó .

0

Đây là cách tôi đã làm nó:

Điểm mà tôi muốn hiển thị OpenFileDialog:

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

DialogResult dr = ofd.ShowDialog(); 

Mã tái định vị:

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

tôi bắt đầu một chủ đề đó sẽ tìm kiếm một cửa sổ với tiêu đề "Mở". (Thường được tìm thấy trong 3 lần lặp hoặc 15 mili giây.) Sau đó, tôi đặt vị trí của nó bằng tay cầm thu được. (Xem tài liệu SetWindowPos để biết thông số vị trí/kích thước.)

Kludgy.

1

Vị trí OpenFileDialog và SaveFileDialog ở góc trên bên trái của khu vực khách hàng của cửa sổ được hiển thị gần đây nhất. Vì vậy, chỉ cần tạo một cửa sổ vô hình mới được định vị nơi bạn muốn hộp thoại xuất hiện trước khi tạo và hiển thị hộp thoại đó.

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

Đủ nếu không muốn sử dụng 'DllImport's. – IAbstract

0

Rất biết ơn BobB đã trả lời câu hỏi này. Có một vài "gotchas" nữa. Bạn phải vượt qua xử lý của PositionForm khi gọi OpenFileDialog1.ShowDialog (PositionForm) nếu không kỹ thuật của BobB không đáng tin cậy trong mọi trường hợp. Ngoài ra, bây giờ W8.1 khởi chạy một điều khiển tập tin mới với SkyDrive trong đó, vị trí thư mục Tài liệu trong điều khiển tệp tin W8.1 hiện đã bị hỏng. Vì vậy, tôi frig fileopen để sử dụng điều khiển W7 cũ bằng cách thiết lập ShowHelp = True.

Đây là mã VB.NET mà tôi đã sử dụng, đóng góp của tôi cho cộng đồng trong trường hợp nó trợ giúp.

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 
1

Tôi gặp sự cố này trong hầu hết ngày hôm qua. Câu trả lời của BobB là câu trả lời giúp tôi nhiều nhất (Cảm ơn BobB).

Bạn thậm chí có thể thực hiện một phương pháp riêng để tạo cửa sổ và đóng cửa sổ đó trước khi gọi phương thức dialog.ShowDialog() và nó vẫn sẽ là trung tâm 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; 
} 

Sau đó gọi nó theo bất kỳ phương pháp nào trước phương pháp 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; 
} 
Các vấn đề liên quan