SendKeys
SendKeys выглядит как хак, но это самый простой способ, и по причинам, описанным ниже, вероятно, более устойчивый в долгосрочной перспективе, чем использование Win32 API.
Использование await Task.Delay(250);
рискованно .Время ожидания может быть слишком коротким, прежде чем в медленной системе появится диалоговое окно, с другой стороны, если время ожидания увеличено, быстрый пользователь может взаимодействовать, конкурируя с автоматизацией SendKeys.
Я рекомендую вам использовать Цикл сообщений, чтобы уведомлять, когда отправлятьКейсы .
bool IsOpenFileDialog = false;
private void openDialog_Click(object sender, EventArgs e)
{
IsOpenFileDialog = true;
openFileDialog1.ShowDialog();
IsOpenFileDialog = false;
}
uint _lastDialogHandle = 0;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (!IsOpenFileDialog) return;
if (m.Msg == 289) //Notify of message loop
{
try
{
uint dialogHandle = (uint)m.LParam; //handle of the file dialog
if (dialogHandle != _lastDialogHandle) //only when not already changed
{
_lastDialogHandle = dialogHandle;
SendKeys.SendWait("+{TAB}");
SendKeys.SendWait("+{TAB}");
SendKeys.SendWait(EscapeSendKeySpecialCharacters("temp.xls"));
//Or try via Win32
//List<string> childWindows = GetDialogChildWindows(dialogHandle);
//TODO set ListView Item
}
}
catch (Exception ex) {}
}
}
private string EscapeSendKeySpecialCharacters(string sentence)
{
sentence = sentence.Replace("+", "{+}");
sentence = sentence.Replace("^", "{^}");
sentence = sentence.Replace("%", "{%}");
sentence = sentence.Replace("~", "{~}");
sentence = sentence.Replace("(", "{(}");
sentence = sentence.Replace(")", "{)}");
return sentence;
}
Примечание: Знак плюс (+), каретка (^), знак процента (%), тильда (~) и скобки () имеют специальные значения для SendKeys.Чтобы указать один из этих символов, заключите его в фигурные скобки ({}).
Так, например, если в имени вашего файла есть круглые скобки, вам нужно экранировать их фигурными скобками:
SendKeys.SendWait("New Text Document - Copy {(}8{)}.txt");
Win32 (попытка - неполная и не работает)
Вы можете попробовать перебрать дочерние окна OpenFileDialogs, чтобы найти элемент управления просмотра списка:
private List<string> GetDialogChildWindows(dialogHandle) {
//IEnumerable<IntPtr> allWindows = EnumWindowsAndChild.EnumAllWindows((IntPtr)dialogHandle, "Dialog");
List<IntPtr> children = EnumWindowsAndChild.GetChildWindows((IntPtr)dialogHandle);
List<string> childWindows = new List<string>();
foreach (IntPtr ptr in children)
{
string s = ptr.ToString() + ", " + EnumWindowsAndChild.GetWindowsTextTitle(ptr) + ", " + EnumWindowsAndChild.GetWindowClassName(ptr);
System.Diagnostics.Debug.WriteLine(s);
childWindows.Add(s);
}
return childWindows;
}
Помощник класса Enum Windows и Child:
public static class EnumWindowsAndChild
{
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static public extern IntPtr GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);
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;
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(HandleRef hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(HandleRef hWnd, StringBuilder lpString, int nMaxCount);
public static string GetWindowsTextTitle(IntPtr hwnd)
{
int capacity = GetWindowTextLength(new HandleRef(null, hwnd)) * 2;
StringBuilder stringBuilder = new StringBuilder(capacity);
GetWindowText(new HandleRef(null, hwnd), stringBuilder, stringBuilder.Capacity);
return stringBuilder.ToString();
}
public static string GetWindowClassName(IntPtr hWnd)
{
StringBuilder buffer = new StringBuilder(128);
GetClassName(hWnd, buffer, buffer.Capacity);
return buffer.ToString();
}
}
Когда у вас есть Hwnd для ListView, вы можете попытаться установить его элемент, но вам нужно будет использовать NativeWindow, и он не будет красивым,см. эту статью, чтобы понять, что я имею в виду: http://www.codeproject.com/Articles/2890/Using-ListView-control-under-Win-API
Как бы мне не хотелось это признавать, это один из редких случаев, когда я предлагал SendKeys вместо Win32 API.Win32 Api могут даже не работать в конце, и SendKeys с большей вероятностью продолжит работать, если / когда API изменятся.Например, мы видели, что с XP до Vista API FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle)
теперь практически бесполезен, поскольку Aero скрывает заголовки Windows, необходимые для параметра windowTitle.Одним из решений является использование Classic Theme, но не многие примут это, поэтому это одна из причин, по которой я бы не стал рассчитывать, что Win32 apis сделает эту конкретную вещь и просто использует SendKeys.См. Здесь:

Я больше не могу заставить работать этот материал: https://bytes.com/topic/c-sharp/answers/262498-openfiledialog-how-select-files-coding, из электронной почты Microsoft Dist,
// Getting the handle of the ListBox in the OpenFileDialog dialog.
uint listviewHandle = FindWindowEx(dialogHandle, 0,
"SHELLDLL_DefView", "");
// Sending message to the ListBox to set the view to Thumbnails
//Icons=0x7029, List=0x702b, Details=0x702c, Thumbnails=0x702d,
Tiles=0x702e
SendMessage(listviewHandle, 0x0111/*WM_COMMAND*/, (uint)0x702d, 0);
// Sending message to the ListBox to select all items.
SendMessage(listviewHandle, 0x0111/*WM_COMMAND*/, (uint)0x00017021,
(uint)0);