คุณจะกำหนดค่า OpenFileDialog ให้เลือกโฟลเดอร์ได้อย่างไร?


251

ใน VS .NET เมื่อคุณเลือกโฟลเดอร์สำหรับโครงการไดอะล็อกที่ดูเหมือน OpenFileDialog หรือ SaveFileDialog จะปรากฏขึ้น แต่ถูกตั้งค่าให้ยอมรับเฉพาะโฟลเดอร์เท่านั้น นับตั้งแต่ฉันได้เห็นสิ่งนี้ฉันอยากรู้ว่ามันเสร็จสิ้นแล้ว ฉันตระหนักถึง FolderBrowserDialog แต่ฉันไม่เคยชอบกล่องโต้ตอบนั้นจริงๆ มันเริ่มเล็กเกินไปและไม่ให้ฉันใช้ประโยชน์จากความสามารถในการพิมพ์เส้นทาง

ตอนนี้ฉันเกือบจะแน่ใจแล้วว่าไม่มีวิธีการทำเช่นนี้จาก. NET แต่ฉันก็อยากรู้ว่าคุณจะทำอย่างไรจากโค้ดที่ไม่มีการจัดการเช่นกัน ขาดการนำกล่องโต้ตอบไปใช้ใหม่อย่างสมบูรณ์ตั้งแต่ต้นคุณจะปรับเปลี่ยนกล่องโต้ตอบเพื่อให้มีพฤติกรรมนี้ได้อย่างไร

ฉันยังต้องการที่จะย้ำว่าฉันรู้ FolderBrowserDialog แต่บางครั้งฉันไม่ชอบที่จะใช้มันนอกเหนือจากการอยากรู้อยากเห็นอย่างแท้จริงถึงวิธีการกำหนดค่าการโต้ตอบในลักษณะนี้ การบอกให้ฉันใช้ FolderBrowserDialog ช่วยให้ฉันรักษาประสบการณ์ UI ที่สอดคล้องกัน แต่ไม่ตอบสนองความอยากรู้ของฉันดังนั้นมันจะไม่นับเป็นคำตอบ

มันไม่ใช่สิ่งที่เฉพาะเจาะจงกับ Vista เช่นกัน ฉันได้เห็นกล่องโต้ตอบนี้ตั้งแต่ VS .NET 2003 ดังนั้นจึงเป็นไปได้ใน Win2k และ WinXP นี่เป็นคำถามที่ว่า "ฉันต้องการทราบวิธีที่เหมาะสมในการทำเช่นนี้" และฉันก็อยากรู้มากกว่านี้ตั้งแต่คำถามแรกที่ฉันต้องการจะทำใน VS 2003 ฉันเข้าใจว่ากล่องโต้ตอบไฟล์ของ Vista มีตัวเลือกให้ทำเช่นนี้ แต่ทำงานได้ใน XP ดังนั้นฉันรู้ว่าพวกเขาทำอะไรบางอย่างเพื่อให้มันทำงาน คำตอบเฉพาะของ Vista ไม่ใช่คำตอบเนื่องจาก Vista ไม่มีอยู่ในบริบทของคำถาม

ปรับปรุง: ฉันยอมรับคำตอบก็อตต์ Wisniewski เพราะมันมาพร้อมกับตัวอย่างการทำงาน แต่ฉันคิดว่าเสิร์จสมควรได้รับเครดิตสำหรับการชี้ไปที่การปรับแต่งโต้ตอบ (ซึ่งเป็นที่ยอมรับน่ารังเกียจจาก .NET แต่มันไม่ทำงาน) และมาร์คไถ่สำหรับการหาที่ MS อาจรีดไดอะล็อกที่กำหนดเองสำหรับงานนี้


7
เพียงวิธีการแก้ปัญหาอย่างง่ายจาก codeproject codeproject.com/Articles/44914/… [กุญแจสู่การ OpenFileDialog เพื่อเลือกทั้งไฟล์และโฟลเดอร์คือการตั้งค่าคุณสมบัติ ValidateNames และ CheckFileExists เป็นเท็จ (dialog.ValidateNames = false; dialog.CheckFileExists = false) และตั้งค่า FileName เป็นคำหลักพิเศษบางอย่างเพื่อให้แน่ใจว่าโฟลเดอร์จะถูกเลือก (dialog.FileName = "การเลือกโฟลเดอร์";).]
Riju

3
ส่งคำตอบนี้เป็นคำตอบสำหรับโครงการของฉัน
CigarDoug

@Riju dialog.FileName = "Folder Selection"ควรจะอยู่dialog.FileName = "Folder Selection."กับช่วงเวลาท้าย? อย่างไรก็ตามฉันไม่สามารถใช้งานได้ใน PowerShell เมื่อคลิก "เปิด" ครั้งที่สอง มันยังคงบอกว่าไม่พบไฟล์แม้ว่า CheckFileExists นั้นควรจะเป็นเท็จ
ComradeJoecool

nvm ในการตั้งค่า powershell dialog.CheckFileExists = 0แทนที่จะเป็นเท็จแก้ไขปัญหาของฉัน
ComradeJoecool

คุณได้ลองใช้Ookii Dialogs สำหรับ WPF แล้วหรือยัง?
C. Augusto Proiete

คำตอบ:


57

ฉันมีกล่องโต้ตอบที่ฉันเขียนเรียกว่ากล่องโต้ตอบ OpenFileOrFolder ที่อนุญาตให้คุณเปิดโฟลเดอร์หรือไฟล์

หากคุณตั้งค่า AcceptFiles เป็น false แสดงว่าทำงานในโหมดโฟลเดอร์ที่ยอมรับเท่านั้น

คุณสามารถดาวน์โหลดแหล่งข้อมูลจาก GitHub ได้ที่นี่


4
น่าสนใจมากและซับซ้อนพอ ๆ กับที่ฉันคิด โอกาสใด ๆ ในการเพิ่มความคิดเห็นและชี้ให้เห็นว่ามันทำอะไร? สิ่งนี้พร้อมกับความคิดเห็นอื่นทำให้ฉันเชื่อว่า MS น่าจะเป็นบทสนทนาของตัวเอง
OwenP

1
ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อพยายามสร้างโซลูชันของคุณ ... น่าเสียดายที่ c ++ ไม่ใช่จุดแข็งของฉัน ... ข้อผิดพลาด 1 ไม่สามารถเปิดได้รวมไฟล์ 'afxres.h'
Ignacio Soler Garcia

1
@SoMoS และคนอื่น ๆ ที่มีปัญหาเดียวกัน: ในไฟล์ WindowsFormsApplication1.csproj แก้ไขบรรทัดที่ 100 ดังนั้นมันจึงตรงกับการตั้งค่าของคุณ ในกรณีของฉันฉันต้องเปลี่ยน "9.0" เป็น "10.0" (สองครั้ง) และลบ "(x86)" (สองครั้ง)
RenniePet

2
ฉันดาวน์โหลดรหัส (zip) และพบไฟล์. h (C) และรวบรวมข้อผิดพลาดเช่นไม่สามารถเปิดไฟล์รวม 'sal.h'
Lei Yang

2
วิธีนี้ไม่สามารถใช้กับ VS2010 และ VS2017 ได้เช่นกัน!
AleX_

49

คุณสามารถใช้FolderBrowserDialogEx - อนุพันธ์ที่สามารถใช้งานได้อีกครั้งของ FolderBrowserDialog ในตัว อันนี้ช่วยให้คุณพิมพ์ในเส้นทางแม้กระทั่งเส้นทาง UNC คุณยังสามารถเรียกดูคอมพิวเตอร์หรือเครื่องพิมพ์ด้วย ทำงานเหมือน FBD ในตัว แต่ ... ดีขึ้น

(แก้ไข: ฉันควรจะชี้ให้เห็นว่ากล่องโต้ตอบนี้สามารถตั้งค่าให้เลือกไฟล์หรือโฟลเดอร์)

รหัสที่มาแบบเต็ม (หนึ่งโมดูล C # สั้น) ฟรี. ใบอนุญาต MS-Public

รหัสที่จะใช้:

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
ขออภัยถ้าฉันโกรธเคืองมันเป็นเรื่องน่าหงุดหงิดที่จะถามคำถามและสะกดคำว่า "ฉันต้องการสิ่งนี้ไม่ใช่สิ่งอื่น ๆ เหล่านี้" และให้ผู้คนแนะนำสิ่งที่ไม่ได้ร้องขออย่างร่าเริง ฉันต้องการกล่องโต้ตอบไฟล์เบราว์เซอร์ไม่ใช่กล่องโต้ตอบเบราว์เซอร์โฟลเดอร์
OwenP

15
วิธีถามคำถามมันฟังดูราวกับว่ากำลังขอกล่องโต้ตอบตัวเลือกโฟลเดอร์ - ไม่ใช่อย่างนั้นหรือ อย่างไรก็ตามนี่คือสิ่งที่ฉันกำลังมองหา +1
ทิม

คำตอบที่ดีที่สุดอย่างแน่นอน
Vasil Popov

1
แต่นั่นไม่ได้เปลี่ยนความจริงที่ว่าคำตอบยังคงเป็นคำตอบเฉพาะการเชื่อมโยง การแสดงวิธีใช้รหัสที่โฮสต์อยู่ที่แหล่งทรัพยากรนอกสถานที่จะเป็นประโยชน์เมื่อลิงก์นั้นใช้งานไม่ได้ชั่วคราวหรือถาวร มีกฎสำหรับเหตุผลและการสนับสนุนนี้ขัดแย้งกับกฎเหล่านั้น
IInspectable

1
ฉันดูคำตอบนี้และเห็นได้ชัดว่าไม่ได้อ้างอิงทรัพยากรนอกสถานที่ ดังนั้น"คำตอบอื่น ๆ "จึงผิดอย่างชัดเจน หากคุณรู้สึกว่าฉันทำปฏิกิริยามากเกินไปคุณอาจจะหยิบยกปัญหาที่ meta เพื่อหารือเกี่ยวกับกฎ ฉันจะไม่ ฉันจะใช้มัน
IInspectable

48

มี Windows API Code Pack มีหลายสิ่งที่เกี่ยวข้องกับเชลล์รวมถึงCommonOpenFileDialogคลาส (ในMicrosoft.WindowsAPICodePack.Dialogsเนมสเปซ) นี่เป็นโซลูชั่นที่สมบูรณ์แบบ - กล่องโต้ตอบแบบเปิดทั่วไปที่มีเฉพาะโฟลเดอร์ที่แสดง

นี่คือตัวอย่างของวิธีการใช้งาน:

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

น่าเสียดายที่ Microsoft ไม่ได้จัดส่งแพ็คเกจนี้อีกต่อไป แต่หลาย ๆ คนได้อัปโหลดไบนารีอย่างไม่เป็นทางการไปยัง NuGet ตัวอย่างหนึ่งที่สามารถพบได้ที่นี่ แพคเกจนี้เป็นเพียงสิ่งเฉพาะเชลล์ หากคุณต้องการผู้ใช้คนเดียวกันก็มีแพ็คเกจอื่น ๆ ที่เสนอฟังก์ชันการทำงานเพิ่มเติมในแพ็คเกจเดิม


1
ฉันไม่ทราบว่านี่เป็นชุดรหัส API ของ Windows - ขอบคุณที่ชี้ให้เห็น
Patrick Klug

10
คลาส CommonOpenFileDialog มีอยู่ใน Windows Vista หรือใหม่กว่าเท่านั้นดังนั้นจะมีข้อยกเว้นสำหรับระบบปฏิบัติการรุ่นเก่า
Rachel

1
คุณช่วยบอกวิธีอ้างอิง Windows API Code Pack ได้ไหม?
ฟ์

1
คลังภาพเก็บถาวรได้ถูกยกเลิก หรือเพื่อให้ลิงค์บอกว่า .. นี่อาจจะเป็นสถานที่ใหม่สำหรับมันได้หรือไม่
เริ่มต้น

3
โดยวิธีการชั้น CommonOpenFileDialog อยู่ใน Microsoft.WindowsAPICodePack.Dialogs namespace (เอาฉันสักครู่เพื่อหามัน)
morgb

35

Ookii.Dialogsแพคเกจประกอบด้วยเสื้อคลุมที่มีการจัดการรอบใหม่ (Vista สไตล์) โฟลเดอร์โต้ตอบเบราว์เซอร์ มันยังลดระดับลงอย่างงดงามบนระบบปฏิบัติการรุ่นเก่า


2
เยี่ยมเลยเป็นโอเพ่นซอร์สลิขสิทธิ์ BSD
Roman Starkov

7
ปัญหาเดียวคือฉันจะไม่ให้ฉันใช้โปรไฟล์ลูกค้า. net framework เป็นเป้าหมาย
Kugel

2
ทางออกที่ดีมาก นี่คือมุมมองของฉันคำตอบที่ดีที่สุด สิ่งที่ฉันค้นหาอยู่มา 3 ปี
ซามูเอล

1
ปัญหาอื่นของการแก้ไขนี้: ไม่อนุญาตให้ผู้ใช้วางเส้นทางที่ไม่มีอยู่ ผู้เยาว์เปรียบเทียบ แต่ยังคงน่าเสียดาย
Roman Starkov

1
ที่ดีที่สุดในทางปฏิบัติคำตอบสำหรับผู้ที่ต้องการOpenFileDialogโต้ตอบโฟลเดอร์สไตล์
น้ำ

27

ดีกว่าที่จะใช้ FolderBrowserDialog สำหรับสิ่งนั้น

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

9
ฉันรู้ว่ามันเป็นการดีกว่าที่จะใช้ FolderBrowserDialog ฉันอยากรู้ว่ามันทำยังไง FolderBrowserDialog มีกลิ่นเหม็นในหลาย ๆ ทาง; แม้ใน Vista จะไม่มีแถบตำแหน่ง ขำ ๆ ว่า MS ที่ดีกว่านั้นจะสามารถหลีกเลี่ยงได้ใน 3 เวอร์ชั่น VS หรือไม่
OwenP

24
FolderBrowserDialog มีปัญหาการใช้งานมากมาย ฉันจะไม่พิจารณานำไปใช้จริงในแอปพลิเคชัน เห็นโพสต์ของฉันสำหรับการโต้ตอบที่มีการใช้งานที่ดีขึ้นมาก
สกอตต์ Wisniewski

6
FolderBrowserDialog ไม่อนุญาตให้: - พิมพ์ / วางเส้นทางแบบเต็มในช่องข้อความที่ด้านล่าง - ใช้แถบ "ลิงค์โปรด" ใน Vista - ใช้การค้นหาบน Vista
decasteljau

89
FolderBrowserDialog เป็น UI ที่น่ากลัวอย่างแท้จริง
mackenir

32
อย่างจริงจังผู้คนโปรดหยุดวางกล่องโต้ตอบที่น่ารำคาญนี้ในแอปพลิเคชันของคุณ มี VERY BAD UI ตามที่เน้นโดยความคิดเห็นก่อนหน้า
Roman Starkov

23

หลังจากการค้นหาหลายชั่วโมงฉันพบคำตอบนี้โดยleetNightShadeกับโซลูชันที่ใช้งานได้

ฉันเชื่อว่ามีสามสิ่งที่ทำให้โซลูชันนี้ดีกว่าสิ่งอื่น ๆ ทั้งหมด

  1. มันใช้งานง่าย มันต้องการเพียงคุณรวมสองไฟล์ (ซึ่งสามารถรวมเป็นหนึ่งต่อไป) ในโครงการของคุณ
  2. มันกลับไปสู่FolderBrowserDialogมาตรฐานเมื่อใช้กับ XP หรือระบบที่เก่ากว่า
  3. ผู้เขียนมอบสิทธิ์ในการใช้รหัสเพื่อจุดประสงค์ใด ๆ ที่คุณเห็นว่าเหมาะสม

    ไม่มีใบอนุญาตเช่นคุณมีอิสระที่จะทำและทำสิ่งใดกับรหัสที่คุณต้องการ

ดาวน์โหลดรหัสที่นี่


@MattDavis: ฉันยืนยันว่ามันทำงานได้บน. NET Framework 4.0 (ทั้งแบบมาตรฐานและโปรไฟล์ลูกค้า) ตรวจสอบให้แน่ใจว่าคุณได้เพิ่ม FolderSelectDialog.cs และ Reflector.cs ลงในโครงการของคุณ สิ่งหนึ่งที่ ... คุณกำลังใช้งาน Windows 8 อยู่หรือไม่? ฉันทดสอบบนคอมพิวเตอร์ Win7
Alex Essilfie

@Alex Essilfie คุณถูกต้อง ฉันต้องทำอะไรผิดพลาดในการดึงมันเข้าไปในโครงการของฉัน ฉันจะลบความคิดเห็นก่อนหน้านี้เพื่อความชัดเจน
แมตต์เดวิส

วิ่งผ่านตัวเลือกหลายตัวและคิดว่าอันนี้ดีที่สุด แนะนำ
เบื่อ

ทำงานใน windows 10 สำหรับฉัน วิธีแก้ปัญหาที่ง่ายดี
David Wilton

ต้องเคารพความล้มเหลวในระบบเก่า
Mike M

17

การคัดลอกเสียงที่แน่นอนทำงานด้วยวิธีนี้ใน Windows XP กล่องโต้ตอบเปิดไฟล์มาตรฐานจะปรากฏขึ้น แต่ฟิลด์ชื่อไฟล์มีข้อความ "ชื่อไฟล์จะถูกละเว้น"

เพิ่งเดาได้ที่นี่ แต่ฉันสงสัยว่าสายอักขระถูกแทรกลงในตัวควบคุมการแก้ไขคำสั่งผสมกล่องทุกครั้งที่มีการเปลี่ยนแปลงที่สำคัญในกล่องโต้ตอบ ตราบใดที่ฟิลด์ไม่ว่างและมีการตั้งค่าสถานะของไดอะล็อกให้ไม่ตรวจสอบการมีอยู่ของไฟล์ไดอะล็อกสามารถปิดได้ตามปกติ

แก้ไข:ง่ายกว่าที่ฉันคิดไว้มาก นี่คือรหัสใน C ++ / MFC คุณสามารถแปลเป็นสภาพแวดล้อมที่คุณเลือก

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

แก้ไข 2:นี่ควรเป็นการแปลเป็น C # แต่ฉันไม่คล่องใน C # ดังนั้นอย่ายิงฉันถ้ามันไม่ทำงาน

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
}

แก้ไข 3:สุดท้ายดูที่กล่องโต้ตอบที่เป็นปัญหาจริงใน Visual Studio 2005 (ฉันไม่สามารถเข้าถึงได้ก่อนหน้านี้) ไม่ใช่กล่องโต้ตอบเปิดไฟล์มาตรฐาน! หากคุณตรวจสอบหน้าต่างใน Spy ++ และเปรียบเทียบกับไฟล์มาตรฐานที่เปิดอยู่คุณจะเห็นว่าโครงสร้างและชื่อคลาสไม่ตรงกัน เมื่อคุณมองอย่างใกล้ชิดคุณสามารถมองเห็นความแตกต่างระหว่างเนื้อหาของกล่องโต้ตอบ ข้อสรุปของฉันคือ Microsoft แทนที่ไดอะล็อกมาตรฐานใน Visual Studio อย่างสมบูรณ์เพื่อให้ความสามารถนี้ โซลูชันหรือสิ่งที่คล้ายกันของฉันจะใกล้เคียงที่สุดเท่าที่คุณจะทำได้เว้นแต่คุณจะเต็มใจเขียนโค้ดของคุณเองตั้งแต่เริ่มต้น


17

ตกลงให้ฉันลองเชื่อมต่อจุดแรก ;-) การเล่นนิดหน่อยด้วย Spy ++ หรือ Winspector แสดงให้เห็นว่ากล่องข้อความโฟลเดอร์ในตำแหน่งโครงการ VS เป็นการปรับแต่งกล่องโต้ตอบมาตรฐาน มันไม่ได้เป็นเขตข้อมูลเดียวกับกล่องข้อความชื่อไฟล์ในกล่องโต้ตอบไฟล์มาตรฐานเช่นหนึ่งใน Notepad

จากนั้นฉันคิดว่า VS ซ่อนชื่อไฟล์และกล่องข้อความ / คอมโบบ็อกซ์และใช้เทมเพลตกล่องโต้ตอบแบบกำหนดเองเพื่อเพิ่มส่วนของตัวเองที่ด้านล่างของกล่องโต้ตอบ

แก้ไข: นี่คือตัวอย่างของการปรับแต่งดังกล่าวและวิธีการทำ (ใน Win32 ไม่ใช่. NET):

m_ofn เป็นโครงสร้าง OPENFILENAME ที่อยู่ภายใต้ไดอะล็อกไฟล์ เพิ่ม 2 บรรทัดเหล่านี้:

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

โดยที่ IDD_FILEDIALOG_IMPORTXLIFF เป็นแม่แบบไดอะล็อกที่กำหนดเองซึ่งจะถูกเพิ่มที่ด้านล่างของไดอะล็อก ดูส่วนที่เป็นสีแดงด้านล่าง (ที่มา: apptranslator.com )ข้อความแสดงแทน

ในกรณีนี้ส่วนที่กำหนดเองเป็นเพียงป้ายกำกับ + การเชื่อมโยงหลายมิติ แต่มันอาจเป็นกล่องโต้ตอบใด ๆ มันอาจมีปุ่มตกลงที่จะให้เราตรวจสอบการเลือกโฟลเดอร์เท่านั้น

แต่เราจะกำจัดส่วนควบคุมบางส่วนในบทสนทนามาตรฐานได้อย่างไรฉันไม่รู้

รายละเอียดเพิ่มเติมในบทความนี้ MSDN


1
ฟังดูเหมือนคำอธิบายบางอย่างที่ฉันเคยได้ยินในอดีต แต่ฉันไม่เคยเห็นการสาธิตแนวคิด มีคำแนะนำในเอกสารประกอบ MSDN เกี่ยวกับการทำเช่นนั้นหรือไม่?
OwenP

10

คุณสามารถคลาสย่อยไดอะล็อกไฟล์และเข้าถึงการควบคุมทั้งหมด แต่ละตัวมีตัวระบุที่สามารถใช้เพื่อรับหมายเลขอ้างอิงหน้าต่าง จากนั้นคุณสามารถแสดงและซ่อนพวกเขาได้รับข้อความจากพวกเขาเกี่ยวกับการเปลี่ยนแปลงการเลือก ฯลฯ ทุกอย่างขึ้นอยู่กับความพยายามที่คุณต้องการ

เราใช้การสนับสนุนระดับ WTL และปรับแต่งกล่องโต้ตอบไฟล์เพื่อรวมแถบสถานที่ที่กำหนดเองและมุมมอง COM ปลั๊กอิน

MSDNให้ข้อมูลเกี่ยวกับวิธีการทำเช่นนี้โดยใช้ Win32, บทความ CodeProject นี้รวมถึงตัวอย่างและบทความ CodeProject นี้แสดงให้เห็นตัวอย่างสุทธิ


10

คุณสามารถใช้รหัสเช่นนี้

  • ตัวกรองคือซ่อนไฟล์
  • ชื่อไฟล์จะซ่อนข้อความแรก

ในการซ่อนกล่องข้อความขั้นสูงสำหรับชื่อไฟล์คุณต้องดู OpenFileDialogEx

รหัส:

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

เรียบง่ายและเป็นสิ่งที่ฉันต้องการสำหรับ Windows 7 ขึ้นไป
Hao Nguyen

ต้องมี OFN_NOVALIDATE ในธงด้วย
Goblin Alchemist

5

ฉันคิดว่าคุณใช้ Vista กับ VS2008? ในกรณีที่ผมคิดว่าตัวเลือก FOS_PICKFOLDERSจะถูกใช้เมื่อเรียกไฟล์ Vista โต้ตอบIFileDialog ฉันกลัวว่าใน. รหัส NET นี้จะเกี่ยวข้องกับรหัส gnarly P / เรียกใช้รหัส interop เพื่อให้ทำงานได้


1
เฉพาะ Vista; ฉันเห็นสิ่งนี้เป็นครั้งแรกใน VS 2003 บน Windows XP
OwenP

2

ทางออกแรก

ฉันพัฒนาสิ่งนี้ให้เป็นไดอะล็อกการเลือกไดอะล็อกการเลือกโฟลเดอร์. NET Win 7 สไตล์โดย Bill Seddon แห่งlyquidity.com (ฉันไม่มีส่วนเกี่ยวข้อง) (ฉันเรียนรู้รหัสของเขาจากคำตอบอื่นในหน้านี้ ) ฉันเขียนของตัวเองเพราะโซลูชันของเขาต้องการคลาส Reflection เพิ่มเติมที่ไม่จำเป็นสำหรับจุดประสงค์ที่มุ่งเน้นนี้ใช้การควบคุมการไหลตามข้อยกเว้นไม่ได้แคชผลลัพธ์ของการสะท้อนกลับ โปรดทราบว่าVistaDialogคลาสสแตติกที่ซ้อนอยู่นั้นคือตัวแปรการสะท้อนคงที่ของมันจะไม่พยายามเติมข้อมูลหากShowวิธีนั้นไม่เคยถูกเรียก มันกลับไปที่กล่องโต้ตอบ pre-Vista หากไม่ได้อยู่ในรุ่น Windows ที่สูงพอ ควรทำงานใน Windows 7, 8, 9, 10 และสูงกว่า (ตามหลักเหตุผล)

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

มันถูกใช้อย่างนั้นในรูปแบบ Windows:

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

แน่นอนว่าคุณสามารถเล่นกับตัวเลือกและคุณสมบัติที่เปิดเผย ตัวอย่างเช่นอนุญาตให้มีการเลือกหลายรายการในกล่องโต้ตอบสไตล์ Vista

ทางออกที่สอง

Simon Mourier ให้คำตอบที่แสดงวิธีการทำงานที่แน่นอนโดยใช้ interop เทียบกับ Windows API โดยตรงถึงแม้ว่าเวอร์ชั่นของเขาจะต้องได้รับการเสริมให้ใช้กล่องโต้ตอบแบบเก่าถ้าใช้ Windows รุ่นเก่า น่าเสียดายที่ฉันไม่พบโพสต์ของเขาเมื่อฉันแก้ปัญหาของฉัน บอกชื่อพิษของคุณ!


ตัวอย่างการใช้งานที่คล้ายกันเพื่อเรียกกล่องโต้ตอบนี้เป็นกล่องโต้ตอบ (เช่นจากแอปประเภทคอนโซล) พร้อมที่ว่างเปล่า: คอมไพล์ออกจากกล่อง: var dialog = new FolderSelectDialog {InitialDirectory = "C: \\", Title = "เลือก a โฟลเดอร์ที่จะนำเข้าเพลงจาก "}; if (dialog.Show ()) {string myFolder = dialog.FileName; }
Philm

หมายเหตุ: ตัวอย่างการใช้งานของฉันเป็นความคิดเห็นยากต่อการอ่านดังนั้น: การเปลี่ยนแปลงที่สำคัญที่สุดสำหรับการใช้งานดั้งเดิม "ตัวอย่าง": ใช้เครื่องหมายจุลภาคระหว่าง InitialDirectory และ Title ..
Philm

1

ลองอันนี้จากCodeproject (เครดิตถึง Nitron):

ฉันคิดว่ามันเป็นกล่องโต้ตอบแบบเดียวกันกับที่คุณพูดถึง - บางทีมันอาจช่วยได้ถ้าคุณเพิ่มภาพหน้าจอ?

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

images.google.com/…ทำวิจัยเมื่อไม่แน่ใจ ฉันอธิบายสิ่งที่ฉันต้องการและ FolderBrowserDialog ได้ถูกตัดสิทธิ์เป็นคำตอบแล้ว
OwenP

"ฉันทราบ FolderBrowserDialog แต่ฉันไม่เคยชอบกล่องโต้ตอบนั้นจริงๆมันเริ่มน้อยเกินไปและไม่ให้ฉันใช้ประโยชน์จากความสามารถในการพิมพ์เส้นทาง" ทำวิจัยด้วยตัวเอง - คุณสามารถพิมพ์เส้นทางในนั้น อย่างไรก็ตามฉันคิดว่ามันเป็นคำถามที่ค่อนข้างคลุมเครือดังนั้นขอให้โชคดีกับมัน
demoncodemonkey

@demoncodemonkey: คุณไม่สามารถพิมพ์ในส่วนของเส้นทางแล้วนำทางไปยังเป้าหมายที่คุณต้องการ โดยไกลไม่สะดวกเท่าตัวเลือกที่ FileOpenDialog เสนอ
Treb

1

บน Vista คุณสามารถใช้IFileDialogพร้อมชุดตัวเลือก FOS_PICKFOLDERS ที่จะทำให้การแสดงหน้าต่างเหมือน OpenFileDialog ที่คุณสามารถเลือกโฟลเดอร์:

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

สำหรับ Windows รุ่นเก่าคุณสามารถใช้เคล็ดลับในการเลือกไฟล์ใดก็ได้ในโฟลเดอร์

การทำงานตัวอย่างเช่นที่ทำงานบน NET Framework 2.0 และต่อมาสามารถพบได้ที่นี่


1

คุณสามารถใช้รหัสเช่นนี้

ตัวกรองเป็นสตริงว่าง ชื่อไฟล์คือ AnyName แต่ไม่ว่างเปล่า

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

6
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่เพื่อประโยชน์ของทุกคนที่ต้องการลองใช้งานจริง ๆ แล้วมันจะไม่ทำงานเว้นแต่ไดเรกทอรีที่คุณต้องการเปิดไม่มีไดเรกทอรีย่อย ดังนั้นหากฉันต้องการให้ผู้ใช้ของฉันเรียกดูโฟลเดอร์และเลือกและเติมเส้นทางโฟลเดอร์ในกล่องข้อความบางกล่องผู้ใช้จะไม่สามารถเลือก C: \ SomeParentDir หากมีไดเรกทอรี C: \ SomeParentDir \ SomeChildDir อยู่เพราะเลือก "เปิด "นำคุณไปยังไดเรกทอรีลูก
จิม

ลองดี .. แต่สิ่งนี้ส่งผลให้ UI แย่มากเพราะ "AnyFile" ในกล่องข้อความกำลังรอให้ผู้ใช้แทนที่ข้อความของมัน .. นอกจากนั้นผู้ใช้ยังสามารถเลือกไฟล์ได้ - ไม่ดีพอ แต่ดีลอง ..
GY


-1

ฉันรู้ว่าคำถามคือการกำหนดค่าของOpenFileDialogแต่เมื่อเห็นว่า Google นำฉันมาที่นี่ฉันก็อาจชี้ให้เห็นว่าถ้าคุณกำลังมองหาโฟลเดอร์เท่านั้นคุณควรจะใช้FolderBrowserDialogแทนการตอบโดยคำถาม SO อื่นด้านล่าง

วิธีการระบุพา ธ โดยใช้กล่องโต้ตอบเปิดไฟล์ใน vb.net


ที่ทำให้เข้าใจผิด 1) มันไม่ใช่ตัวเลือกเดียว 2) มันไม่มีทางเลือกที่ดีในกรณีส่วนใหญ่; ยังคงต้องใช้รหัสน้อยที่สุดซื้อขายโดยใช้เวลาของผู้ใช้มากขึ้น
Meow Cat 2012
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.