ADVERTENCIA: puesto de largo con una gran cantidad de código.
Cuando navega por el control del navegador web a una carpeta del sistema de archivos, el control del navegador web aloja una ventana de vista de shell que a su vez aloja la vista de lista del explorador. De hecho, esto es exactamente lo mismo que el proceso Explorer, así como los diálogos de archivos e Internet Explorer. Esta ventana de shell no es un control de modo que no existen métodos que pueden ser llamados en él o eventos que pueden ser suscrito a pero pueden recibir mensajes de ventanas y puede ser sub-clasificado.
Resulta que la parte de su pregunta relacionada con la configuración automática de la vista es en realidad bastante fácil. En caso Navigated de su control del explorador web, simplemente encontrar el identificador de la ventana vista de shell y enviar un mensaje WM_COMMAND con una constante de cáscara en particular (SHVIEW_REPORT). Este es un comando no documentado pero se admite en todas las plataformas de Windows hasta e incluyendo Windows 2008 y es casi seguro que será en Windows 7.Algo de código para agregar a la forma de su navegador web demuestra esto:
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;
}
Cada vez que el navegador web se desplaza a una nueva ventana (incluyendo cuando una carpeta se abre desde dentro de la vista de explorador) una nueva ventana de vista de la cáscara se crea por lo el mensaje se debe volver a enviar a la nueva ventana en cada evento Navegado.
Para la segunda parte de su pregunta, desea recibir eventos de la vista de lista del explorador. Esto es bastante más difícil que la primera parte. Para hacer esto, necesitaría subclasificar la ventana de vista de lista y luego monitorear los mensajes de Windows para los que le interesan (como WM_LBUTTONDBLCLK). Para subclasificar una ventana, necesitaría crear su propia clase derivada de la clase NativeWindow y asignarle el identificador de la ventana que necesita supervisar. A continuación, puede anular su procedimiento de Ventana y manejar los diversos mensajes como desee. A continuación se muestra un ejemplo de creación de un evento de doble clic: es relativamente simple, pero obtener un amplio acceso a la vista de lista del explorador puede implicar mucho más trabajo de lo que está dispuesto a hacer.
Agregue esto a su forma:
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);
}
y estas dos líneas al manejador Navigated evento (justo después de la SendMessage):
m_Explorer = new ExplorerListView(m_ShellView);
m_Explorer.ItemExecuted += OnExplorerItemExecuted;
A continuación, agregue las siguientes clases:
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;
}
}
Esto debería darle una idea de lo que tendría que hacer. Si desea eventos más que simples, es posible que desee buscar un control alternativo, aunque por lo que he visto en las áreas gratuitas y de bajo costo, existen algunos controles bastante decentes, pero todos tienen algunos caprichos y no ofrecen un explorador perfecto. experiencia.
Recuerde que este código se compiló bastante rápido sin manejo de errores o comentarios e ignorando varios problemas, como múltiples elementos seleccionados, así que úselo como guía y bajo su propio riesgo.
Lo que encontré útil es el (comercial) [componente ShellBrowser] (http://www.jam-software.com/shellbrowser_net/?language=EN). –