我可以在 C:\Users\Public\Documents 中启动 DotNet 的 OpenFileDialog 吗?

Can I launch DotNet's OpenFileDialog in C:\Users\Public\Documents?

有没有办法启动 C:\Users\Public\Documents 文件夹中的 OpenFileDialog

我正在使用 DotNet 框架编写 C# 应用程序。我正在尝试启动 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 .

实际结果
打开文件对话框打开。顶部文本框显示 > This PC > Documents ,底部文本框显示 world.txt 。如果我点击顶部的文本框,它会显示 Documents 。显示的文件夹内容与C:\Users\Public\Documents的内容相同

我尝试过的东西
我已经在以下代码行之后停止了 Visual Studio 调试器中的代码:
OpenFileDialog dlg = new OpenFileDialog();

在即时 Window 中,我执行了如下代码:

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:\C:\Users\C:\Users\PublicC:\Users\Public\Documents\之间使用了C:\WINDOWS\System32\cmd.execd

我尝试过的结果

我的环境
我是 运行 Microsoft Visual Studio Community 2015 Version 14.0.23107.0 D14REL,使用 Microsoft Visual C# 2015。我的操作系统是 Windows 10 Pro。

看来不可能!

您可以在下面link看到它是.net framework 中的一个错误:( msdn link 您可以在最后一条评论中找到:

It is hard to believe but:

It is a bug and nothing else.

尽管如 Silver 所述,这是一个错误,但可以在不同的线程上使用带有 WM_SETTEXT 的 SendMessage API 粗略绕过,尽管至少可以说 ,它很可能会起作用。

我使用 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;
            }
        }

    }
}

有点老套,但可行

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

dialog.AutoUpgradeEnabled = false;

对话框看起来有点dated/flat/"old school",但它至少显示了正确的内容!

你会认为明显的答案是使用 Environment.SpecialFolder.CommonDo‌​‌​cuments,但这似乎与 Windows 10 上的 Environment.SpecialFolder.MyDo‌​‌​cuments 完全相同。这一定是.NET!

我 运行 今天解决了这个问题,找到了一个对我有用的解决方案,可能对其他人也有用。只需将子文件夹添加到 Public 文档,然后将其用作初始目录即可。将您的东西存储在特定于应用程序的子文件夹中而不是仅仅存储在根目录中可能是更好的做法。像这样:

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