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

Вставка экземпляра File Explorer в форму приложения Windows Forms

Приложение My (С#,.NET 3.5) создает файлы и, помимо поднятия событий, которые могут быть обнаружены и отреагированы, я хочу отобразить целевую папку для пользователя в форме. Список файлов отображается в том же виде, что и другая информация.

Я использую экземпляр элемента управления WebBrowser (System.Windows.Forms.WebBrowser), затем перейдя в папку. Это показывает представление по умолчанию окна проводника с панелью сводки файлов слева и файлами в представлении "Плитки" (большой значок и текст).

Например,

wb.Navigate(@"c:\path\to\folder\");

Я хотел бы отключить панель и просмотреть список файлов в представлении "Детали". Пользователь может получить это через контекстное меню правой кнопкой мыши, но я бы хотел, чтобы он автоматически появлялся.

Я бы предпочел не создавать собственный TreeView, DataGridView или что-то еще; элемент управления WebBrowser выполняет все обновление и повторную сортировку, а также "бесплатно".

Есть ли лучший способ? Другой элемент управления для использования или некоторые дополнительные аргументы для перехода к элементу управления?

И если бы я мог ловить события (например, файлы были выбраны/переименованы/двойным щелчком и т.д.), тогда все будет лучше!

4b9b3361

Ответ 1

Для обработки переименования, удаления и создания другой настройки вам необходимо написать свой собственный файловый проводник. Управление WebBrowser не подходит для ваших нужд. Это просто оболочка над компонентом ActiveX.
Вы должны проверить эту статью кодекса. Он содержит реализацию файлового проводника. Есть еще несколько образцов файлового браузера:
один
два

Ответ 2

ПРЕДУПРЕЖДЕНИЕ: длинный пост с большим количеством кода.

При перемещении элемента управления веб-браузера в папку файловой системы элемент управления веб-браузером размещает окно просмотра оболочки, которое, в свою очередь, отображает представление списка проводников. На самом деле это то же самое, что и процесс Explorer, а также диалоговые окна файлов и Internet Explorer. Это окно оболочки не является элементом управления, поэтому нет методов, которые могут быть вызваны на нем, или событий, на которые можно подписаться, но он может получать сообщения Windows и может быть подклассифицирован.

Оказывается, что часть вашего вопроса, связанная с настройкой вида на детали автоматически, на самом деле довольно проста. В элементе управления веб-браузером Navigated просто найдите дескриптор окна просмотра оболочки и отправьте ему сообщение WM_COMMAND с определенной константой оболочки (SHVIEW_REPORT). Это недокументированная команда, но она поддерживается на всех платформах Windows вплоть до Windows 2008, и почти наверняка будет в Windows 7. Некоторый код для добавления в форму вашего веб-браузера демонстрирует это:

    private delegate int EnumChildProc(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg,
        IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern int EnumChildWindows(IntPtr hWndParent,
        EnumChildProc lpEnumFunc, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName,
        int nMaxCount);

    private const int WM_COMMAND = 0x0111;
    private const int SHVIEW_REPORT = 0x702C;
    private const string SHELLVIEW_CLASS = "SHELLDLL_DefView";

    private IntPtr m_ShellView;

    void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
    {
        m_ShellView = IntPtr.Zero;
        EnumChildWindows(webBrowser1.Handle, EnumChildren, IntPtr.Zero);
        if (m_ShellView != IntPtr.Zero)
        {
            SendMessage(m_ShellView, WM_COMMAND, (IntPtr)SHVIEW_REPORT, (IntPtr)0);
        }
    }

    private int EnumChildren(IntPtr hwnd, IntPtr lParam)
    {
        int retval = 1;

        StringBuilder sb = new StringBuilder(SHELLVIEW_CLASS.Length + 1);
        int numChars = GetClassName(hwnd, sb, sb.Capacity);
        if (numChars == SHELLVIEW_CLASS.Length)
        {
            if (sb.ToString(0, numChars) == SHELLVIEW_CLASS)
            {
                m_ShellView = hwnd;
                retval = 0;
            }
        }

        return retval;
    }

Каждый раз, когда веб-браузер переходит в новое окно (в том числе, когда открывается папка в представлении проводника), создается новое окно просмотра оболочки, поэтому сообщение должно быть повторно отправлено в новое окно в каждом навигационном событии.

Для второй части вашего вопроса вы хотите получать события из списка просмотра проводника. Это немного сложнее, чем первая часть. Для этого вам нужно подклассифицировать окно просмотра списка, а затем следить за сообщениями Windows для тех, кто вас интересует (например, WM_LBUTTONDBLCLK). Для того, чтобы подклассом было окно, вам нужно создать свой собственный класс, полученный из класса NativeWindow, и назначить ему дескриптор окна, которое необходимо контролировать. Затем вы можете переопределить свою процедуру Window и обрабатывать различные сообщения по своему усмотрению. Ниже приведен пример создания события двойного щелчка - он относительно прост, но для получения расширенного доступа к представлению списка проводников может потребоваться гораздо больше работы, чем вы готовы.

Добавьте это в форму:

    private ExplorerListView m_Explorer;

    void OnExplorerItemExecuted(object sender, ExecuteEventArgs e)
    {
        string msg = string.Format("Item to be executed: {0}{0}{1}", 
            Environment.NewLine, e.SelectedItem);
        e.Cancel = (MessageBox.Show(msg, "", MessageBoxButtons.OKCancel) 
            == DialogResult.Cancel);
    }

и эти две строки обработчику событий Navigated (сразу после SendMessage):

    m_Explorer = new ExplorerListView(m_ShellView);
    m_Explorer.ItemExecuted += OnExplorerItemExecuted;

Затем добавьте следующие классы:

class ExplorerListView : NativeWindow
{

    public event EventHandler<ExecuteEventArgs> ItemExecuted;

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg,
        IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent,
        IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    private const int WM_LBUTTONDBLCLK = 0x0203;

    private const int LVM_GETNEXTITEM = 0x100C;
    private const int LVM_GETITEMTEXT = 0x1073;

    private const int LVNI_SELECTED = 0x0002;

    private const string EXPLORER_LISTVIEW_CLASS = "SysListView32";

    public ExplorerListView(IntPtr shellViewHandle)
    {
        base.AssignHandle(FindWindowEx(shellViewHandle, IntPtr.Zero, 
            EXPLORER_LISTVIEW_CLASS, null));
        if (base.Handle == IntPtr.Zero)
        {
            throw new ArgumentException("Window supplied does not encapsulate an explorer window.");
        }
    }


    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_LBUTTONDBLCLK:
                if (OnItemExecution() != 0) return;
                break;
            default:
                break;
        }
        base.WndProc(ref m);
    }

    private int OnItemExecution()
    {
        int cancel = 0;
        ExecuteEventArgs args = new ExecuteEventArgs(GetSelectedItem());
        EventHandler<ExecuteEventArgs> temp = ItemExecuted;
        if (temp != null)
        {
            temp(this, args);
            if (args.Cancel) cancel = 1;
        }
        return cancel;
    }

    private string GetSelectedItem()
    {
        string item = null;

        IntPtr pStringBuffer = Marshal.AllocHGlobal(2048);
        IntPtr pItemBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LVITEM)));

        int selectedItemIndex = SendMessage(base.Handle, LVM_GETNEXTITEM, (IntPtr)(-1), (IntPtr)LVNI_SELECTED).ToInt32();
        if (selectedItemIndex > -1)
        {
            LVITEM lvi = new LVITEM();
            lvi.cchTextMax = 1024;
            lvi.pszText = pStringBuffer;
            Marshal.StructureToPtr(lvi, pItemBuffer, false);
            int numChars = SendMessage(base.Handle, LVM_GETITEMTEXT, (IntPtr)selectedItemIndex, pItemBuffer).ToInt32();
            if (numChars > 0)
            {
                item = Marshal.PtrToStringUni(lvi.pszText, numChars);
            }
        }

        Marshal.FreeHGlobal(pStringBuffer);
        Marshal.FreeHGlobal(pItemBuffer);

        return item;
    }

    struct LVITEM
    {
        public int mask;
        public int iItem;
        public int iSubItem;
        public int state;
        public int stateMask;
        public IntPtr pszText;
        public int cchTextMax;
        public int iImage;
        public IntPtr lParam;
        public int iIndent;
        public int iGroupId;
        int cColumns; // tile view columns
        public IntPtr puColumns;
        public IntPtr piColFmt;
        public int iGroup;

    }
}

public class ExecuteEventArgs : EventArgs
{
    public string SelectedItem { get; private set; }
    public bool Cancel { get; set; }

    internal ExecuteEventArgs(string selectedItem)
    {
        SelectedItem = selectedItem;
    }
}

Это должно дать вам представление о том, что вам нужно сделать. Если вы хотите более чем достаточно простые события, вы можете захотеть найти альтернативный контроль, хотя из того, что я видел в свободных и недорогих областях, есть довольно приличные элементы управления, но у всех их есть некоторые причуды и не даст бесшовный проводник опыт.

Помните, что этот код был составлен достаточно быстро без обработки ошибок или комментариев и игнорирования нескольких проблем, таких как несколько выбранных элементов, поэтому используйте его как руководство и на свой страх и риск.

Ответ 3

Программное обеспечение LogicNP имеет два элемента управления (FileView и ShComboBox), которые выполняют то, что вы ищете: http://www.ssware.com/fldrview.htm

Вы можете загрузить пробную версию со своей страницы, однако для нее требуется ~ 130 $.

Ответ 4

Я написал библиотеку, которая могла бы вам помочь. Вы можете найти его по адресу: http://gong-shell.sourceforge.net/

Элемент управления, который вы ищете, - это ShellView. Там есть учебники о том, как создать простой клон Windows Explorer только в нескольких строках.

Примечание для пользователей .NET 4.0. В настоящее время Gong-shell разбит на 4.0. Структура вносила изменения в Interop, и она будет создавать просто отлично, но вызывать разные проблемы при взаимодействии с shell32 (в частности, shellicon api, что приводит к неуправляемому разыменованию нулевого указателя).

Ответ 5

Gong-shell работает достаточно хорошо, и он прост в использовании. И бесплатно.

Ответ 6

Если вы счастливы только в Windows Vista и обмениваете COM, IExplorerBrowser может быть приемлемым для вас.

Эта статья проекта кода показывает ее использование в MFC, но по крайней мере один другой человек, кажется, получил его, чтобы работать на С# после некоторых усилий.

Новый API предоставляет значительно большую программируемость, чем просто перехват сообщений, но он (очевидно) бесполезен для старых платформ.

Ответ 7

Ознакомьтесь с этой статьей здесь, она показывает, как это сделать в .NET и WinForms. Выполнение этого способа дает полный контроль над тем, что видит пользователь.

Я использовал его в одном из моих приложений, и он работает очень хорошо. Вы можете отображать значок/детали/список и останавливать перемещение пользователя в другие каталоги (что часто является проблемой отображения стандартных диалогов файлов/каталогов.

Я использую его, чтобы показать экран, подобный приведенному ниже ниже http://img7.imageshack.us/img7/7647/screenshotbaf.png:

Ответ 9

Если вы хотите открыть другое окно для отображения содержимого целевой папки, вы можете использовать System.Windows.Forms.OpenFileDialog или SaveFileDialog или наследовать от FileDialog и расширять его.

Чтобы разрешить пользователю выбирать папку, вы можете использовать FolderBrowserDialog, хотя в качестве пользователя мне не нравится этот элемент управления.

Помогает ли это, или вам абсолютно необходимо встроить элемент управления в свою форму?

Асаф