Làm thế nào để bạn cấu hình một OpenFileDialog để chọn các thư mục?


251

Trong VS .NET, khi bạn đang chọn thư mục cho một dự án, một hộp thoại trông giống như OpenFileDialog hoặc SaveFileDialog được hiển thị, nhưng được thiết lập để chỉ chấp nhận các thư mục. Kể từ khi tôi nhìn thấy điều này, tôi muốn biết nó đã được thực hiện như thế nào. Tôi biết về FolderBrowserDialog, nhưng tôi chưa bao giờ thực sự thích hộp thoại đó. Nó bắt đầu quá nhỏ và không cho phép tôi tận dụng khả năng gõ một con đường.

Bây giờ tôi gần như chắc chắn không có cách nào để làm điều này từ .NET, nhưng tôi cũng tò mò về cách bạn làm điều đó từ mã không được quản lý. Không thực hiện lại hoàn toàn hộp thoại từ đầu, làm thế nào để bạn sửa đổi hộp thoại để có hành vi này?

Tôi cũng muốn nói lại rằng tôi biết về FolderBrowserDialog nhưng đôi khi tôi không muốn sử dụng nó, ngoài việc thực sự tò mò về cách định cấu hình hộp thoại theo cách này. Nói với tôi rằng chỉ sử dụng FolderBrowserDialog giúp tôi duy trì trải nghiệm UI nhất quán nhưng không thỏa mãn sự tò mò của tôi nên nó sẽ không được coi là một câu trả lời.

Nó cũng không phải là một thứ cụ thể của Vista; Tôi đã thấy hộp thoại này kể từ VS .NET 2003, vì vậy nó có thể thực hiện được trong Win2k và WinXP. Đây không phải là câu hỏi "Tôi muốn biết cách thích hợp để làm điều này" và nhiều câu hỏi "Tôi đã tò mò về điều này kể từ lần đầu tiên tôi muốn làm điều đó trong VS 2003". Tôi hiểu rằng hộp thoại tệp của Vista có một tùy chọn để thực hiện việc này, nhưng nó đang hoạt động trong XP nên tôi biết họ đã làm gì đó để nó hoạt động. Câu trả lời dành riêng cho Vista không phải là câu trả lời, vì Vista không tồn tại trong ngữ cảnh câu hỏi.

Cập nhật: Tôi chấp nhận câu trả lời Scott Wisniewski vì nó đi kèm với một mẫu làm việc, nhưng tôi nghĩ rằng Serge xứng đáng tín dụng cho trỏ đến các tùy thoại (đó là phải thừa nhận là khó chịu từ NET nhưng nó không làm việc) và Mark Ransom cho tìm ra rằng MS có lẽ cuộn một hộp thoại tùy chỉnh cho nhiệm vụ này.


7
chỉ là một giải pháp đơn giản từ codeproject codeproject.com/Articles/44914/, [Chìa khóa để nhận OpenFileDialog để chọn cả hai tệp và thư mục là đặt các thuộc tính ValidateNames và CheckFileExists thành false (hộp thoại.ValidateNames = false; hộp thoại và đặt FileName thành một số từ khóa đặc biệt để đảm bảo rằng các thư mục được chọn (hộp thoại.FileName = "Lựa chọn thư mục";).]
Riju

3
Gửi điều này như một câu trả lời, nó đã làm công việc cho dự án của tôi.
Xì gà

@Riju được dialog.FileName = "Folder Selection"cho là dialog.FileName = "Folder Selection."với thời gian kéo dài? dù sao tôi cũng không thể làm cho nó hoạt động trong powershell trên lần nhấp thứ hai của "Open". Nó liên tục nói rằng tập tin không được tìm thấy, mặc dù CheckFileExists được cho là sai
ComradeJoecool

nvm, trong cài đặt powershell dialog.CheckFileExists = 0thay vì sai đã giải quyết vấn đề của tôi
ComradeJoecool

Câu trả lời:


57

Tôi có một hộp thoại mà tôi đã viết được gọi là hộp thoại OpenFileOrFolder cho phép bạn mở một thư mục hoặc một tệp.

Nếu bạn đặt giá trị AcceptFiles của nó thành false, thì nó chỉ hoạt động ở chế độ thư mục chấp nhận.

Bạn có thể tải nguồn từ GitHub tại đây


4
Rất thú vị, và chắc chắn phức tạp như tôi đã hình dung. Bất kỳ cơ hội để chú thích nó và chỉ ra những gì nó làm? Điều này cùng với các bình luận khác khiến tôi tin rằng MS có lẽ chỉ cần cuộn hộp thoại của riêng họ.
OwenP

1
Tôi gặp lỗi sau khi cố gắng xây dựng giải pháp của bạn ... thật không may, c ++ không phải là một trong những điểm mạnh của tôi ... Lỗi 1 không thể mở bao gồm tệp 'afxres.h'.
Ignacio Soler Garcia

1
@SoMoS và các vấn đề khác có cùng một vấn đề: trong tệp WindowsFormsApplication1.csproj chỉnh sửa dòng 100 để nó phù hợp với thiết lập của bạn. Trong trường hợp của tôi, tôi đã phải thay đổi "9.0" thành "10.0" (hai lần) và xóa "(x86)" (hai lần).
RenniePet

2
Tôi đã tải xuống mã (zip) và tìm thấy tệp .h (C) và được biên dịch với lỗi như không thể mở bao gồm tệp 'sal.h'.
Lôi Dương

2
Giải pháp này cũng không hoạt động trên VS2010 và VS2017!
AleX_

49

Bạn có thể sử dụng FolderBrowserDialogEx - một dẫn xuất có thể sử dụng lại của FolderBrowserDialog tích hợp. Cái này cho phép bạn gõ vào một đường dẫn, thậm chí là đường dẫn UNC. Bạn cũng có thể duyệt tìm máy tính hoặc máy in với nó. Hoạt động giống như FBD tích hợp, nhưng ... tốt hơn.

(EDIT: Tôi nên chỉ ra rằng hộp thoại này có thể được đặt để chọn tệp hoặc thư mục.)

Mã nguồn đầy đủ (một mô-đun C # ngắn). Miễn phí. Giấy phép MS-công.

Mã để sử dụng nó:

var dlg1 = new Ionic.Utils.FolderBrowserDialogEx();
dlg1.Description = "Select a folder to extract to:";
dlg1.ShowNewFolderButton = true;
dlg1.ShowEditBox = true;
//dlg1.NewStyle = false;
dlg1.SelectedPath = txtExtractDirectory.Text;
dlg1.ShowFullPathInEditBox = true;
dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

// Show the FolderBrowserDialog.
DialogResult result = dlg1.ShowDialog();
if (result == DialogResult.OK)
{
    txtExtractDirectory.Text = dlg1.SelectedPath;
}

7
Xin lỗi nếu tôi đã xúc phạm, thật khó chịu khi đặt câu hỏi và đánh vần "Tôi muốn điều cụ thể này, không phải những điều khác" và mọi người vui vẻ đề nghị điều không được yêu cầu. Tôi muốn một hộp thoại trình duyệt tập tin, không phải là một hộp thoại trình duyệt thư mục.
OwenP

15
Cách mà câu hỏi được diễn đạt, nó nghe có vẻ như tôi đang yêu cầu một hộp thoại chọn thư mục - có phải vậy không? Dù sao, đây chính xác là những gì tôi đang tìm kiếm +1
Tim

Chắc chắn là câu trả lời tốt nhất cho đến nay
Vasil Popov

1
Điều đó không thay đổi thực tế, rằng câu trả lời vẫn là câu trả lời chỉ liên kết. Hiển thị cách sử dụng mã được lưu trữ tại tài nguyên ngoài trang web sẽ không còn hữu ích, khi liên kết đó cũng trở nên tạm thời hoặc vĩnh viễn không khả dụng. Các quy tắc là có lý do, và sự đóng góp này mâu thuẫn với các quy tắc đó.
IInspectable

1
Tôi đã xem câu trả lời này và dường như nó không tham khảo tài nguyên ngoài trang web. Vì vậy, "mọi câu trả lời khác" rõ ràng là sai. Nếu bạn cảm thấy mình phản ứng thái quá, có lẽ bạn nên nêu vấn đề tại meta để thảo luận về các quy tắc. Tôi sẽ không. Tôi sẽ chỉ áp dụng chúng.
IInspectable

48

Có gói mã API Windows. Nó có rất nhiều thứ liên quan đến shell, bao gồm cả CommonOpenFileDialoglớp (trong Microsoft.WindowsAPICodePack.Dialogskhông gian tên). Đây là giải pháp hoàn hảo - hộp thoại mở thông thường chỉ có các thư mục được hiển thị.

Dưới đây là một ví dụ về cách sử dụng nó:

CommonOpenFileDialog cofd = new CommonOpenFileDialog();
cofd.IsFolderPicker = true;
cofd.ShowDialog();

Thật không may, Microsoft không còn gửi gói này nữa, nhưng một số người đã tải lên các tệp nhị phân không chính thức cho NuGet. Một ví dụ có thể được tìm thấy ở đây . Gói này chỉ là những thứ cụ thể vỏ. Nếu bạn cần nó, cùng một người dùng có một số gói khác cung cấp nhiều chức năng hơn trong gói ban đầu.


1
Tôi không biết rằng đây là trong Gói mã API của Windows - cảm ơn vì đã chỉ ra điều này.
Patrick Klug

10
Lớp CommonOpenFileDialog chỉ tồn tại trên Windows Vista trở lên, do đó sẽ đưa ra một ngoại lệ trên các hệ điều hành cũ
Rachel

1
Bạn có thể vui lòng cho biết cách tham khảo Gói mã API của Windows không?
jeff

1
Thư viện Lưu trữ đã nghỉ hưu. , hoặc vì vậy, liên kết nói .. Đây có thể là nơi mới cho nó?
Mặc định

3
Nhân tiện, lớp CommonOpenFileDialog nằm trong không gian tên Microsoft.WindowsAPICodePack.Dialogs (tôi mất một lúc để tìm thấy nó).
morgb 17/2/2016

35

Các Ookii.Dialogs gói chứa một wrapper quản lý xung quanh mới (Vista-style) thư mục hộp thoại trình duyệt. Nó cũng xuống cấp một cách duyên dáng trên các hệ điều hành cũ.


2
Thật tuyệt, đó là nguồn mở được cấp phép theo kiểu BSD!
Roman Starkov

7
vấn đề duy nhất là, tôi sẽ không cho phép tôi sử dụng hồ sơ khách hàng khung .net làm mục tiêu.
Kugel

2
Giải pháp rất hay. Đây là trong quan điểm của tôi Câu trả lời tốt nhất. Chính xác những gì tôi đã tìm kiếm từ 3 năm.
Samuel

1
Một vấn đề khác với giải pháp này: nó không cho phép người dùng dán một đường dẫn không tồn tại. Một thứ nhỏ, tương đối, nhưng vẫn đáng tiếc.
Roman Starkov

1
Câu trả lời thực tế tốt nhất cho những người muốn một OpenFileDialoghộp thoại thư mục kiểu.
thủy

27

Tốt hơn để sử dụng FolderBrowserDialog cho điều đó.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}

9
Tôi nhận thức được rằng tốt hơn là sử dụng FolderBrowserDialog. Tôi tò mò làm thế nào nó được thực hiện bất kể. Dù sao đi nữa, FolderBrowserDialog vẫn bốc mùi theo nhiều cách; ngay cả trong Vista nó cũng không có thanh địa điểm. Thật buồn cười nếu MS tốt hơn đã tránh nó trong 3 phiên bản VS cho đến nay.
OwenP

24
FolderBrowserDialog có nhiều vấn đề về khả năng sử dụng. Tôi sẽ không xem xét thực sự đưa nó vào một ứng dụng. Xem bài đăng của tôi cho một hộp thoại có khả năng sử dụng tốt hơn nhiều
Scott Wisniewski

6
FolderBrowserDialog không cho phép: - nhập / dán các đường dẫn đầy đủ vào trường văn bản ở dưới cùng - sử dụng thanh "Liên kết yêu thích" trên Vista - sử dụng Tìm kiếm trên Vista
decasteljau

89
FolderBrowserDialog là một giao diện người dùng thực sự khủng khiếp.
mackenir

32
Nghiêm túc, mọi người, xin vui lòng ngừng đưa hộp thoại gây phiền nhiễu này vào các ứng dụng của bạn. Nó có giao diện người dùng RẤT BAD như được nhấn mạnh bởi các bình luận trước đó.
Roman Starkov

23

Sau nhiều giờ tìm kiếm, tôi đã tìm thấy câu trả lời này của leetNightShade cho một giải pháp hiệu quả .

Có ba điều tôi tin rằng làm cho giải pháp này tốt hơn nhiều so với tất cả những thứ khác.

  1. Nó rất dễ sử dụng. Nó chỉ yêu cầu bạn bao gồm hai tệp (có thể được kết hợp thành một tệp dù sao) trong dự án của bạn.
  2. Nó rơi trở lại để chuẩn FolderBrowserDialog khi được sử dụng trên XP hoặc các hệ thống cũ.
  3. Tác giả cấp quyền sử dụng mã cho bất kỳ mục đích nào bạn thấy phù hợp.

    Không có giấy phép như bạn có thể tự do lấy và làm với mã những gì bạn sẽ làm.

Tải mã tại đây .


@MattDavis: Tôi đã xác nhận rằng nó hoạt động trên .NET Framework 4.0 (cả Hồ sơ khách hàng và Tiêu chuẩn). Chỉ cần đảm bảo rằng bạn đã thêm cả DirectorySelectDialog.cs và Reflector.cs vào dự án của bạn. Một điều mặc dù ... bạn đang chạy trên Windows 8? Tôi đã thử nghiệm trên máy tính Win7.
Alex Essilfie

@Alex Essilfie, bạn đúng rồi. Tôi phải làm gì đó sai khi kéo nó vào dự án của mình. Tôi sẽ xóa bình luận trước đó của tôi cho rõ ràng.
Matt Davis

Chạy qua nhiều lựa chọn và nghĩ rằng cái này là tốt nhất. Khuyến cáo.
Jaded

Làm việc trong windows 10 cho tôi. Giải pháp đơn giản tốt
David Wilton

phải tôn trọng chuyển đổi dự phòng trong các hệ thống cũ
Mike M

17

Bản sao âm thanh chính xác hoạt động theo cách này trên Windows XP. Hộp thoại mở tệp tiêu chuẩn được hiển thị, nhưng trường tên tệp chứa văn bản "Tên tệp sẽ bị bỏ qua".

Chỉ cần đoán ở đây, nhưng tôi nghi ngờ chuỗi được đưa vào điều khiển chỉnh sửa hộp tổ hợp mỗi khi có một thay đổi đáng kể được thực hiện cho hộp thoại. Miễn là trường không trống và các cờ hộp thoại được đặt thành không kiểm tra sự tồn tại của tệp, hộp thoại có thể được đóng bình thường.

Chỉnh sửa: điều này dễ dàng hơn nhiều so với tôi nghĩ. Đây là mã trong C ++ / MFC, bạn có thể dịch nó sang môi trường bạn chọn.

CFileDialog dlg(true, NULL, "Filename will be ignored", OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_PATHMUSTEXIST | OFN_READONLY, NULL, this);
dlg.DoModal();

Chỉnh sửa 2: Đây phải là bản dịch sang C #, nhưng tôi không rành về C # vì vậy đừng bắn tôi nếu nó không hoạt động.

OpenFileDialog openFileDialog1 = new OpenFileDialog();

openFileDialog1.FileName = "Filename will be ignored";
openFileDialog1.CheckPathExists = true;
openFileDialog1.ShowReadOnly = false;
openFileDialog1.ReadOnlyChecked = true;
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;

if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
    // openFileDialog1.FileName should contain the folder and a dummy filename
}

Chỉnh sửa 3: Cuối cùng đã xem hộp thoại thực tế trong câu hỏi, trong Visual Studio 2005 (Tôi không có quyền truy cập vào nó trước đó). Nó không phải là hộp thoại mở tập tin tiêu chuẩn! Nếu bạn kiểm tra các cửa sổ trong Spy ++ và so sánh chúng với một tệp tiêu chuẩn đang mở, bạn sẽ thấy rằng cấu trúc và tên lớp không khớp. Khi bạn nhìn kỹ, bạn cũng có thể phát hiện ra một số khác biệt giữa nội dung của các hộp thoại. Kết luận của tôi là Microsoft đã thay thế hoàn toàn hộp thoại tiêu chuẩn trong Visual Studio để cung cấp cho nó khả năng này. Giải pháp của tôi hoặc một cái gì đó tương tự sẽ gần như bạn có thể nhận được, trừ khi bạn sẵn sàng tự viết mã từ đầu.


17

OK, hãy để tôi thử kết nối dấu chấm đầu tiên ;-) Chơi một chút với Spy ++ hoặc Winspector cho thấy hộp văn bản Thư mục trong Vị trí dự án VS là một tùy chỉnh của hộp thoại tiêu chuẩn. Đây không phải là cùng một trường với hộp văn bản tên tệp trong hộp thoại tệp tiêu chuẩn, chẳng hạn như trường trong Notepad.

Từ đó, tôi hình dung, VS ẩn tên tệp và hộp văn bản filetype và sử dụng một mẫu hộp thoại tùy chỉnh để thêm phần của chính nó vào dưới cùng của hộp thoại.

EDIT: Đây là một ví dụ về tùy chỉnh như vậy và cách thực hiện (trong Win32. Không phải .NET):

m_ofn là cấu trúc OPENFILENAME làm cơ sở cho hộp thoại tệp. Thêm 2 dòng sau:

  m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_IMPORTXLIFF);
  m_ofn.Flags |= OFN_ENABLETEMPLATE;

trong đó IDD_FILEDIALOG_IMPORTXLIFF là một mẫu hộp thoại tùy chỉnh sẽ được thêm vào dưới cùng của hộp thoại. Xem phần màu đỏ dưới đây. (nguồn: apptranslator.com )văn bản thay thế

Trong trường hợp này, phần tùy chỉnh chỉ là nhãn + siêu liên kết nhưng nó có thể là bất kỳ hộp thoại nào. Nó có thể chứa một nút OK cho phép chúng tôi xác nhận chỉ chọn thư mục.

Nhưng làm thế nào chúng ta sẽ loại bỏ một số điều khiển trong phần tiêu chuẩn của hộp thoại, tôi không biết.

Chi tiết hơn trong bài viết MSDN này .


1
Nghe có vẻ như một số lời giải thích tôi đã nghe trong quá khứ, nhưng tôi chưa bao giờ thấy một minh chứng nào về khái niệm này. Có hướng dẫn trong tài liệu MSDN về làm như vậy không?
OwenP

10

Bạn có thể phân lớp hộp thoại tập tin và có quyền truy cập vào tất cả các điều khiển của nó. Mỗi cái có một định danh có thể được sử dụng để có được tay cầm cửa sổ của nó. Sau đó, bạn có thể hiển thị và ẩn chúng, nhận thông báo từ chúng về các thay đổi lựa chọn, v.v. Tất cả phụ thuộc vào mức độ bạn muốn thực hiện.

Chúng tôi đã sử dụng hỗ trợ lớp WTL và tùy chỉnh hộp thoại tệp để bao gồm thanh địa điểm tùy chỉnh và chế độ xem COM của trình cắm.

MSDN cung cấp thông tin về cách thực hiện việc này bằng Win32, bài viết CodeProject này bao gồm một ví dụbài viết CodeProject này cung cấp một ví dụ .NET .


10

Bạn có thể sử dụng mã như thế này

  • Bộ lọc đang ẩn tập tin
  • Tên tệp được ẩn văn bản đầu tiên

Để nâng cao ẩn hộp văn bản cho tên tệp, bạn cần xem OpenFileDialogEx

Mật mã:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}

Đơn giản và là những gì tôi cần cho Windows 7+
Hao Nguyen

Ngoài ra OFN_NOVALIDATE được yêu cầu trong các cờ
Nhà giả kim yêu tinh

5

Tôi giả sử bạn đang sử dụng Vista trên VS2008? Trong trường hợp đó, tôi nghĩ rằng tùy chọn FOS_PICKFOLDERS đang được sử dụng khi gọi hộp thoại tệp Vista IFileDialog . Tôi e rằng trong mã .NET, điều này sẽ liên quan đến rất nhiều mã P / Gọi liên tục để hoạt động.


1
Đặc thù của Vista; Lần đầu tiên tôi thấy điều này trên VS 2003 trên Windows XP.
OwenP

2

Giải pháp đầu tiên

Tôi đã phát triển nó như là một phiên bản dọn dẹp của hộp thoại chọn thư mục kiểu .NET Win 7 của Bill Seddon của lyquids.com (Tôi không có liên kết). (Tôi đã học được mã của anh ấy từ một câu trả lời khác trên trang này ). Tôi đã tự viết vì giải pháp của anh ta yêu cầu một lớp Reflection bổ sung không cần thiết cho mục đích tập trung này, sử dụng điều khiển luồng dựa trên ngoại lệ, không lưu trữ kết quả của các cuộc gọi phản ánh. Lưu ý rằng VistaDialoglớp tĩnh lồng nhau là để các biến phản xạ tĩnh của nó không cố gắng được điền nếu Showphương thức không bao giờ được gọi. Nó rơi trở lại hộp thoại trước Vista nếu không phải là phiên bản Windows đủ cao. Nên hoạt động trong Windows 7, 8, 9, 10 và cao hơn (về mặt lý thuyết).

using System;
using System.Reflection;
using System.Windows.Forms;

namespace ErikE.Shuriken {
    /// <summary>
    /// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions
    /// </summary>
    public class FolderSelectDialog {
        private string _initialDirectory;
        private string _title;
        private string _fileName = "";

        public string InitialDirectory {
            get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
            set { _initialDirectory = value; }
        }
        public string Title {
            get { return _title ?? "Select a folder"; }
            set { _title = value; }
        }
        public string FileName { get { return _fileName; } }

        public bool Show() { return Show(IntPtr.Zero); }

        /// <param name="hWndOwner">Handle of the control or window to be the parent of the file dialog</param>
        /// <returns>true if the user clicks OK</returns>
        public bool Show(IntPtr hWndOwner) {
            var result = Environment.OSVersion.Version.Major >= 6
                ? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
                : ShowXpDialog(hWndOwner, InitialDirectory, Title);
            _fileName = result.FileName;
            return result.Result;
        }

        private struct ShowDialogResult {
            public bool Result { get; set; }
            public string FileName { get; set; }
        }

        private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title) {
            var folderBrowserDialog = new FolderBrowserDialog {
                Description = title,
                SelectedPath = initialDirectory,
                ShowNewFolderButton = false
            };
            var dialogResult = new ShowDialogResult();
            if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK) {
                dialogResult.Result = true;
                dialogResult.FileName = folderBrowserDialog.SelectedPath;
            }
            return dialogResult;
        }

        private static class VistaDialog {
            private const string c_foldersFilter = "Folders|\n";

            private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
            private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
            private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
            private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
            private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
            private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
            private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
            private readonly static uint s_fosPickFoldersBitFlag = (uint) s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialogNative+FOS")
                .GetField("FOS_PICKFOLDERS")
                .GetValue(null);
            private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
                .GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
                .GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
            private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
            private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
            private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");

            public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title) {
                var openFileDialog = new OpenFileDialog {
                    AddExtension = false,
                    CheckFileExists = false,
                    DereferenceLinks = true,
                    Filter = c_foldersFilter,
                    InitialDirectory = initialDirectory,
                    Multiselect = false,
                    Title = title
                };

                var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
                s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
                s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint) s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
                var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
                s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);

                try {
                    int retVal = (int) s_showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle });
                    return new ShowDialogResult {
                        Result = retVal == 0,
                        FileName = openFileDialog.FileName
                    };
                }
                finally {
                    s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
                }
            }
        }

        // Wrap an IWin32Window around an IntPtr
        private class WindowWrapper : IWin32Window {
            private readonly IntPtr _handle;
            public WindowWrapper(IntPtr handle) { _handle = handle; }
            public IntPtr Handle { get { return _handle; } }
        }
    }
}

Nó được sử dụng như vậy trong Mẫu Windows:

var dialog = new FolderSelectDialog {
    InitialDirectory = musicFolderTextBox.Text,
    Title = "Select a folder to import music from"
};
if (dialog.Show(Handle)) {
    musicFolderTextBox.Text = dialog.FileName;
}

Tất nhiên bạn có thể chơi xung quanh với các tùy chọn của nó và những đặc tính mà nó thể hiện. Ví dụ, nó cho phép multiselect trong hộp thoại kiểu Vista.

Giải pháp thứ hai

Simon Mourier đã đưa ra một câu trả lời cho thấy cách thực hiện chính xác cùng một công việc bằng cách sử dụng interop dựa trên API Windows, mặc dù phiên bản của anh ta sẽ phải được bổ sung để sử dụng hộp thoại kiểu cũ hơn nếu trong phiên bản Windows cũ hơn. Thật không may, tôi đã không tìm thấy bài viết của anh ấy khi tôi tìm ra giải pháp của mình. Đặt tên cho chất độc của bạn!


Ví dụ sử dụng tương tự để gọi hộp thoại tốt này là hộp thoại (ví dụ: từ các ứng dụng loại bảng điều khiển) với tay cầm trống: biên dịch ngay hộp: var hộp thoại = new FolderSelectDialog {InitialDirectory = "C: \\", Title = "Chọn một thư mục để nhập nhạc từ "}; if (hộp thoại.Show ()) {string myFolder = hộp thoại.FileName; }
Philm

Lưu ý: Ví dụ về cách sử dụng của tôi dưới dạng nhận xét rất khó đọc, do đó: Thay đổi quan trọng nhất đối với "ví dụ" sử dụng ban đầu: Sử dụng dấu phẩy giữa InitialDirectory và Title ..
Philm

1

Hãy thử cái này từ Codeproject (tín dụng cho Nitron):

Tôi nghĩ đó là cùng một hộp thoại mà bạn đang nói đến - có lẽ nó sẽ hữu ích nếu bạn thêm ảnh chụp màn hình?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}

image.google.com.vn Làm nghiên cứu khi không chắc chắn. Tôi đã mô tả những gì tôi muốn, và FolderBrowserDialog đã bị loại như là một câu trả lời.
OwenP

"Tôi biết về FolderBrowserDialog, nhưng tôi chưa bao giờ thực sự thích hộp thoại đó. Nó bắt đầu quá nhỏ và không cho phép tôi tận dụng khả năng gõ một đường dẫn." Tự làm một số nghiên cứu - bạn có thể gõ một con đường trong đó. Dù sao tôi nghĩ đó là một câu hỏi mơ hồ, thật may mắn với nó.
demcodemonkey

@demoncodemonkey: Bạn không thể nhập một phần của đường dẫn và sau đó điều hướng đến mục tiêu bạn muốn. Cho đến nay không thuận tiện như các tùy chọn mà FileOpenDialog cung cấp.
Treb

1

Trên Vista, bạn có thể sử dụng IFileDialog với tùy chọn FOS_PICKFOLDERS. Điều đó sẽ khiến hiển thị cửa sổ giống OpenFileDialog nơi bạn có thể chọn các thư mục:

var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);

if (frm.Show(owner.Handle) == S_OK) {
    IShellItem shellItem;
    frm.GetResult(out shellItem);
    IntPtr pszString;
    shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
    this.Folder = Marshal.PtrToStringAuto(pszString);
}

Đối với Windows cũ hơn, bạn luôn có thể dùng mẹo để chọn bất kỳ tệp nào trong thư mục.

Ví dụ hoạt động trên .NET Framework 2.0 trở lên có thể tìm thấy ở đây .


1

Bạn có thể sử dụng mã như thế này

Bộ lọc là chuỗi rỗng. Tên tệp là AnyName nhưng không trống

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;

6
Tôi biết đây là một bài viết cũ, nhưng vì lợi ích của bất kỳ ai muốn dùng thử, nó không thực sự hoạt động trừ khi thư mục bạn muốn mở hoàn toàn không có thư mục con. Vì vậy, nếu tôi muốn cho phép người dùng của mình duyệt đến một thư mục và chọn nó, và điền vào đường dẫn thư mục trong một số hộp văn bản, người dùng không bao giờ có thể chọn C: \ someParentDir nếu thư mục C: \ someParentDir \ someChildDir tồn tại, vì chọn "Mở "Chỉ cần đưa bạn đến thư mục con.
Jim

Thử rất tốt .. nhưng điều này dẫn đến giao diện người dùng khủng khiếp là "AnyFile" trong hộp văn bản chỉ chờ người dùng ghi đè văn bản của mình .. ngoài ra người dùng cũng có thể chọn tệp - không đủ tốt. nhưng hãy cố gắng ..
GY


-1

Tôi biết câu hỏi là về cấu hình OpenFileDialognhưng khi thấy Google đưa tôi đến đây tôi cũng có thể chỉ ra rằng nếu bạn CHỈ tìm kiếm các thư mục, bạn nên sử dụng FolderBrowserDialogThay vì được trả lời bởi một câu hỏi SO khác bên dưới

Làm cách nào để chỉ định đường dẫn sử dụng hộp thoại mở tệp trong vb.net?


Gây hiểu lầm. 1) Đó không phải là sự lựa chọn duy nhất; 2) Không có lựa chọn tốt trong hầu hết các trường hợp; Tuy nhiên, nó đòi hỏi ít mã nhất, được giao dịch bởi thời gian dành cho người dùng cuối nhiều hơn.
Mèo Meow 2012
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.