2016-11-13 85 views
6

有沒有辦法在C:\Users\Public\Documents文件夾中啓動OpenFileDialog我可以在C: Users Public Documents中啓動DotNet的OpenFileDialog嗎?

我正在寫一個C#應用程序,使用DotNet框架。我正在嘗試啓動OpenFileDialogInitialDirectory"C:\\Users\\Public\\Documents\\"FileName"world.txt"。不幸的是,OpenFileDialog將我放入Documents快捷方式,而不是C:\Users\Public\Documents

預期結果
我期望看到的OpenFileDialog開放,與顯示> This PC > Windows7_OS (C:) > Users > Public > Documents頂部文本框,顯示world.txt底部文本框。我希望如果我點擊頂部文本框,它會顯示C:\Users\Public\Documents

實際結果
打開OpenFileDialog。頂部文本框顯示> This PC > Documents,底部文本框顯示world.txt。如果我點擊頂部文本框,它會顯示Documents。顯示的文件夾內容是而不是,與C:\Users\Public\Documents的內容相同。

事情我已經試過
我已經停止在Visual Studio調試器的代碼下面的代碼行後:
OpenFileDialog dlg = new OpenFileDialog();

在立即窗口,我已經執行的代碼如下所示:

dlg.FileName = "world.txt" 
? dlg.FileName 
dlg.InitialDirectory = "C:\\NonExistentDirectory\\"; 
dlg.ShowDialog(); 
dlg.InitialDirectory = "C:\\"; 
dlg.ShowDialog(); 
dlg.InitialDirectory = "C:\\Users\\"; 
dlg.ShowDialog(); 
dlg.InitialDirectory = "C:\\Users\\Public\\"; 
dlg.ShowDialog(); 
dlg.InitialDirectory = "C:\\Users\\Public\\Documents\\"; 
dlg.ShowDialog(); 

我取消了每個對話框。

我用C:\WINDOWS\System32\cmd.execdC:\C:\Users\C:\Users\PublicC:\Users\Public\Documents\之間。事情

結果我都試過

  • dlg.InitialDirectory = "C:\\NonExistentDirectory\\",對話框的文件夾最初顯示爲This PC > Documents > Visual Studio 2015 > Projects > SimpleGame > Controller > bin > Debug"。點擊文本框會導致它顯示C:\Users\Owner\Documents\Visual Studio 2015\Projects\SimpleGame\Controller\bin\Debug。因此,我假設OpenFileDialog通過不更改目錄來靜默地處理無效的InitialDirectory。在這種情況下,它默認爲我項目的裝配箱的Debug文件夾。

  • dlg.InitialDirectory"C:\\""C:\\Users\\""C:\\Users\\Public\\"該對話框的行爲與預期相同。點擊頂部文本框分別產生C:\C:\UsersC:\Users\Public

  • dlg.InitialDirectory = "C:\\Users\\Public\\Documents\\"對話框行爲不正確。頂部文本框顯示> This PC > Documents,底部文本框顯示world.txt。如果我點擊頂部文本框,它會顯示Documents。顯示的文件夾內容是而不是,與C:\Users\Public\Documents的內容相同。

  • 使用cmd.exe讓我cd與預期的文件夾之間,包括到C:\Users\Public\Documents

我的環境
我正在運行Microsoft的Visual Studio 2015年的社區版本14.0.23107.0 D14REL,使用Microsoft Visual C#2015年,我的操作系統是Windows 10專業版。

+0

可能是一個特權的東西?你有沒有試過以管理員身份運行vs? – Noctis

+1

我也在使用Windows 10 Pro,並可以確認此行爲。請注意,如果您使用'dlg.InitialDirectory =「C:\\ Users \\ Public \\ Music \\」;'或'dlg.InitialDirectory = $「C:\\ Users \\ {Environment.UserName} \\ Documents \\「;'然後對話框將打開到相應的庫。但是,如果您指定了作爲自定義庫一部分的目錄的路徑,則該對話框將打開到該物理目錄。當打開一個包含['KNOWNFOLDERID'](https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx)的庫的目錄時,對話框可能會變得「聰明」。 – BACON

+0

您是否嘗試過使用'Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments)'檢索目錄? –

回答

1

如果您正在使用System.Windows.Forms.OpenFileDialog您可以設置:

dialog.AutoUpgradeEnabled = false; 

對話框會顯得有點過時/平/「老同學「但它至少顯示正確的內容!

1

看來這是不可能的!

您可以在下面的鏈接,它是在.NET框架:(錯誤看到 msdn link 你可以在最後的評論發現:

這是很難相信,但:

這是一個錯誤,沒有別的。

+0

我相信這可以在不同的線程上使用Win32 SendMessage API和WM_SETTEXT來完成,儘管至少可以說很難說,它很可能會工作。 – Stavm

+0

如果你會發佈一個工作解決方案,我會upvote它,並刪除我的答案...(但如果你失敗,請upvote我) – silver

+0

@silver - 請不要刪除你的答案。我很高興能得到兩個不同的有用答案,併爲他們兩人提供支持。 – Jasper

2

雖然銀象說,這是一個錯誤,但可以通過SendMessage函數API大致繞過與WM_SETTEXT上不同的線程雖然hackish 說至少,它很可能會工作。

我已經放在一起使用NSGaga's post一些髒代碼段來顯示概念的證明,這個原始示例不應該按原樣使用。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading; 
using System.Windows.Forms; 

namespace WindowsFormsApplication13 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      OpenFileDialog dlg = new OpenFileDialog(); 

      //start a thread to change the dialog path just before displaying it to the user 
      Thread posThread = new Thread(setDialogPath); 
      posThread.Start(); 

      //display dialog to the user 
      DialogResult dr = dlg.ShowDialog(); 
     } 

     [DllImport("user32.dll")] 
     static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName); 
     [DllImport("user32.dll")] 
     static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, string lParam); 
     [DllImport("user32.dll")] 
     static extern IntPtr PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 
     [DllImport("user32.Dll")] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam); 
     [DllImport("user32.dll", CharSet = CharSet.Auto)] 
     static extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount); 

     private void setDialogPath() 
     { 
      const string FULL_PATH = "C:\\Users\\Public\\Documents"; 

      //messages 
      const int WM_SETTEXT = 0xC; 
      const int WM_KEYDOWN = 0x100; 
      const int WM_KEYUP = 0x101; 
      //enter key code 
      const int VK_RETURN = 0x0D; 

      //dialog box window handle 
      IntPtr _window_hwnd; 

      //how many attempts to detect the window 
      int _attempts_count = 0; 

      //get the dialog window handle 
      while ((_window_hwnd = FindWindow(IntPtr.Zero, "Open")) == IntPtr.Zero) 
       if (++_attempts_count > 100) 
        return; 
       else 
        Thread.Sleep(500); //try again 

      //in it - find the path textbox's handle. 
      var hwndChild = EnumAllWindows(_window_hwnd, "Edit").FirstOrDefault(); 

      //set the path 
      SendMessage(hwndChild, WM_SETTEXT, 0, FULL_PATH); 

      //apply the path (send 'enter' to the textbox) 
      PostMessage(hwndChild, WM_KEYDOWN, VK_RETURN, 0); 
      PostMessage(hwndChild, WM_KEYUP, VK_RETURN, 0); 
     } 


     public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam); 

     private static bool EnumWindow(IntPtr handle, IntPtr pointer) 
     { 
      GCHandle gch = GCHandle.FromIntPtr(pointer); 
      List<IntPtr> list = gch.Target as List<IntPtr>; 
      if (list == null) 
       throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>"); 
      list.Add(handle); 
      return true; 
     } 

     public static List<IntPtr> GetChildWindows(IntPtr parent) 
     { 
      List<IntPtr> result = new List<IntPtr>(); 
      GCHandle listHandle = GCHandle.Alloc(result); 
      try 
      { 
       Win32Callback childProc = new Win32Callback(EnumWindow); 
       EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle)); 
      } 
      finally 
      { 
       if (listHandle.IsAllocated) 
        listHandle.Free(); 
      } 
      return result; 
     } 

     public static string GetWinClass(IntPtr hwnd) 
     { 
      if (hwnd == IntPtr.Zero) 
       return null; 
      StringBuilder classname = new StringBuilder(100); 
      IntPtr result = GetClassName(hwnd, classname, classname.Capacity); 
      if (result != IntPtr.Zero) 
       return classname.ToString(); 
      return null; 
     } 

     public static IEnumerable<IntPtr> EnumAllWindows(IntPtr hwnd, string childClassName) 
     { 
      List<IntPtr> children = GetChildWindows(hwnd); 
      if (children == null) 
       yield break; 
      foreach (IntPtr child in children) 
      { 
       if (GetWinClass(child) == childClassName) 
        yield return child; 
       foreach (var childchild in EnumAllWindows(child, childClassName)) 
        yield return childchild; 
      } 
     } 

    } 
} 

的hackish,但可行

+0

我已經修改了這段代碼,並將其添加到了我的程序中。我似乎有一個運行時緩存問題。 (我注意到,當我啓動程序時,我的程序的其他功能非常慢,稍後會變得更快)。在程序的一個給定運行中,第一次使用此代碼打開文件時,「OpenFileDialog」仍然會到'文件'中。隨後,我打開一個文件正常工作,'OpenFileDialog'進入'C:\ Users \ Public \ Documents'文件夾。 – Jasper

+0

當我構建發佈模式時,此代碼間歇性地工作。正如我之前提到的,這個代碼在第一次使用後以調試模式工作。在發佈模式下,它在第一次使用時不起作用;它適用於第二次使用;並在隨後的使用中間歇性地工作。 – Jasper

1

你可能會認爲明顯的答案是使用Environment.SpecialFolder.CommonDo‌​‌​cuments,但這似乎與Windows 10上的Environment.SpecialFolder.MyDo‌​‌​cuments完全相同。這必定是.NET中的一個錯誤!

我今天遇到了這個問題,並找到了一個解決方案,爲我工作,並可能爲別人工作。只需將一個子文件夾添加到公共文檔中,然後將其用作初始目錄。無論如何,將文件存儲在特定於應用程序的子文件夾中而不僅僅是根文件中可能是更好的做法。像這樣:

Path.Combine(Environment.SpecialFolder.CommonDocuments, "SomeSubfolder"). 
+0

這是否給你「C:\ Users \ Public \ Documents \ SomeSubfolder \」? – Jasper

+0

是的,這正是它所做的!在不添加子文件夾的情況下,CommonDocuments只是普通文件不會按照您的預期工作。但是,只要你添加子文件夾,你就能得到你想要的東西 – StalePhish

相關問題