Подтвердить что ты не робот

Может ли OpenFileDialog автоматически выбрать файл со значением, установленным в FileName, если установлен InitialDirectory?

Это nit picky, но почему файл автоматически не выбирается, если он существует, и оба FileName и InitialDirectory установлены правильно?

У меня есть OpenFileDialog с настройками FileName и InitialDirectory, и файлы существуют в этой папке. Почему не выбран файл при запуске метода ShowDialog()?

Файл не выбран, но было бы неплохо, если бы он был выбран, поэтому мне не пришлось бы прокручивать вниз, чтобы выбрать следующий соседний файл.

Любые предложения?

4b9b3361

Ответ 1

Возможно, он не идеален, но как-то он оправдывает ожидания.

У меня есть Button, который показывает OpenFileDialog событие click. Асинхронный метод, который будет SendKeys в OpenFileDialog.

    private async void button1_Click(object sender, EventArgs e){
                string initialDir = "directory\\";
                string FileName = "filename.smthng";
                string combinedDir = initialDir + FileName;
                if (File.Exists(combinedDir)) // if there is a file with that name at that directory
                {
                    openFileDialog1.InitialDirectory = initialDir; // setting directory name
                    openFileDialog1.FileName = FileName; // filename
                    BeginInvoke((Action)(() => openFileDialog1.ShowDialog())); // we need to use BeginInvoke to continue to the following code.
                    await SendKey(FileName); // Sends Key to Dialog 
                }
                else // if there is not file with that name works here because no keys need to send.
                {
                    openFileDialog1.InitialDirectory = initialDir;
                    openFileDialog1.FileName = FileName;
                    openFileDialog1.ShowDialog();
                }

    }

    private async Task SendKey(string FileName){
            await Task.Delay(250); // Wait for the Dialog shown at the screen
            SendKeys.SendWait("+{TAB}"); // First Shift + Tab moves to Header of DataGridView of OpenFileDialog
            SendKeys.SendWait("+{TAB}"); // Second Shift + Tab moves to first item of list
            SendKeys.SendWait(FileName); // after sending filename will directly moves it to the file that we are looking for
    }

Результат

openfiledialog

Изменить 1;

Хорошо, для .Net 3.5 существует также TaskParalelLibrary, но использование Thread будет намного проще.

 Thread t;
 private const string initialDir = "C:\\";
 private const string FileName = "test.txt";
 private void button1_Click(object sender, EventArgs e){
       string combinedDir = initialDir + FileName;
       if (File.Exists(combinedDir)) // if there is a file with that name at that directory
            {
                openFileDialog1.InitialDirectory = initialDir; // setting directory name
                openFileDialog1.FileName = FileName; // filename
                BeginInvoke((Action)(() => openFileDialog1.ShowDialog())); // we need to use BeginInvoke to continue to the following code.
                t = new Thread(new ThreadStart(SendKey)); // Sends Key to Dialog with an seperate Thread.
                t.Start(); // Thread starts.
            }
            else // if there is not file with that name works here because no keys need to send.
            {
                openFileDialog1.InitialDirectory = initialDir;
                openFileDialog1.FileName = FileName;
                openFileDialog1.ShowDialog();
            }
        }

        private void SendKey()
        {
            Thread.Sleep(100); // Wait for the Dialog shown at the screen
            SendKeys.SendWait("+{TAB}"); // First Shift + Tab moves to Header of DataGridView of OpenFileDialog
            SendKeys.SendWait("+{TAB}"); // Second Shift + Tab moves to first item of list
            SendKeys.SendWait(FileName); // after sending filename will directly moves it to the file that we are looking for
        }

Надежда помогает,

Ответ 2

SendKeys

SendKeys кажется взломанным, но он самый простой и по причинам, объясняемым ниже, вероятно, более устойчив в долгосрочной перспективе, чем использование API Win32.

Оказывание на await Task.Delay(250); является рискованным. С другой стороны, таймаут может быть слишком быстрым, прежде чем диалог покажет медленную систему, с другой стороны, если время ожидания увеличено, быстрый пользователь может взаимодействовать, конкурируя с автоматизацией SendKeys.

Я рекомендую вам использовать Message Loop для уведомления о том, когда 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, чтобы найти элемент управления listview:

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.

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