有没有办法在C:\Users\Public\Documents
文件夹中启动OpenFileDialog
?
我正在使用DotNet框架编写C#应用程序。我正在尝试发布一个InitialDirectory
,"C:\\Users\\Public\\Documents\\"
FileName
和"world.txt"
OpenFileDialog
。很遗憾,Documents
将我置于C:\Users\Public\Documents
快捷方式而不是> This PC > Windows7_OS (C:) > Users > Public > Documents
。
预期结果
我希望看到OpenFileDialog打开,顶部文本框显示world.txt
,底部文本框显示C:\Users\Public\Documents
。我希望如果我点击顶部文本框,它会显示> This PC > Documents
。
实际结果
OpenFileDialog打开。顶部文本框显示world.txt
,底部文本框显示Documents
。如果我点击顶部文本框,则会显示C:\Users\Public\Documents
。显示的文件夹内容不与OpenFileDialog dlg = new OpenFileDialog();
的内容相同。
我尝试过的事情
我在以下代码行之后停止了Visual Studio调试器中的代码:
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.exe
我取消了每个对话框。
我在cd
和C:\
以及C:\Users\
和C:\Users\Public
之间使用C:\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
。在这种情况下,它默认为我的项目的程序集的bin dlg.InitialDirectory
文件夹。
当"C:\\"
为"C:\\Users\\"
或"C:\\Users\\Public\\"
或C:\
时,对话框的行为符合预期。点击顶部文本框会分别生成C:\Users
或C:\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
,包括<br>
。
我的环境
我正在使用Microsoft Visual C#2015运行Microsoft Visual Studio社区2015版本14.0.23107.0 D14REL。我的操作系统是Windows 10 Pro。
答案 0 :(得分:2)
尽管如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;
}
}
}
}
Hackish,但可行
答案 1 :(得分:1)
答案 2 :(得分:1)
如果您使用的是System.Windows.Forms.OpenFileDialog,则可以设置:
dialog.AutoUpgradeEnabled = false;
对话框看起来有点陈旧/平坦/&#34;旧学校&#34;但它确实至少显示正确的内容!
答案 3 :(得分:1)
您会认为显而易见的答案是使用Environment.SpecialFolder.CommonDocuments
,但这似乎与Windows 10上的Environment.SpecialFolder.MyDocuments
完全相同。这必定是.NET中的错误!
我今天遇到了这个问题,找到了一个对我有用的解决方案,可能对其他人有用。只需将子文件夹添加到公共文档,然后将其用作初始目录。最好的做法是将您的东西存储在特定于应用程序的子文件夹中,而不是仅仅存储在根目录中。像这样:
Path.Combine(Environment.SpecialFolder.CommonDocuments, "SomeSubfolder").