AVERTISSEMENT: après long avec beaucoup de code.
Lorsque vous déplacez le contrôle du navigateur Web vers un dossier du système de fichiers, le contrôle du navigateur Web héberge une fenêtre de vue du shell qui à son tour héberge la vue de la liste des explorateurs. En fait, c'est exactement la même chose que le processus Explorer, ainsi que les boîtes de dialogue de fichiers et Internet Explorer. Cette fenêtre shell n'est pas un contrôle donc il n'y a pas de méthodes qui peuvent être appelées ou d'événements auxquels on peut s'abonner mais elle peut recevoir des messages Windows et elle peut être sous-classée.
Il s'avère que la partie de votre question traitant de la configuration automatique de la vue est en fait assez facile. Dans l'événement Navigated de votre navigateur Web, recherchez simplement le handle dans la fenêtre de vue du shell et envoyez-lui un message WM_COMMAND avec une constante de shell particulière (SHVIEW_REPORT). Il s'agit d'une commande non documentée, mais elle est prise en charge sur toutes les plates-formes Windows jusqu'à et y compris Windows 2008 et sera presque certainement sur Windows 7.Une partie du code à ajouter à votre formulaire de navigateur Web démontre ceci:
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;
}
Chaque fois que le navigateur Web accède à une nouvelle fenêtre (y compris quand un dossier est ouvert depuis l'explorateur) une nouvelle fenêtre de vue shell est créé afin le message doit être renvoyé à la nouvelle fenêtre dans chaque événement Navigated.
Pour la deuxième partie de votre question, vous aimeriez recevoir des événements de la liste de l'explorateur. C'est un peu plus difficile que la première partie. Pour ce faire, vous devez sous-classer la fenêtre d'affichage de la liste, puis surveiller les messages Windows pour ceux qui vous intéressent (tels que WM_LBUTTONDBLCLK). Afin de sous-classer une fenêtre, vous devez créer votre propre classe dérivée de la classe NativeWindow et lui assigner le handle de la fenêtre que vous devez surveiller. Vous pouvez ensuite remplacer sa procédure Window et gérer les différents messages comme vous le souhaitez. Vous trouverez ci-dessous un exemple de création d'un événement à double clic: il est relativement simple, mais pour accéder à la vue de la liste d'explorateurs, il faut beaucoup plus de travail que ce que vous êtes prêt à faire.
Ajoutez ceci à votre formulaire:
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);
}
et ces deux lignes au gestionnaire d'événements Navigated (juste après le SendMessage):
m_Explorer = new ExplorerListView(m_ShellView);
m_Explorer.ItemExecuted += OnExplorerItemExecuted;
ajouter ensuite les classes suivantes:
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;
}
}
Cela devrait vous donner une idée de ce que vous devez faire. Si vous voulez plus que des événements assez simples, vous voudrez peut-être chercher un contrôle alternatif, mais d'après ce que j'ai vu dans les zones gratuites et peu coûteuses, il y a des contrôles assez corrects mais ils ont tous quelques bizarreries expérience. Rappelez-vous que ce code a été mis en place assez rapidement sans erreur de gestion ou de commentaires et en ignorant plusieurs problèmes tels que plusieurs éléments sélectionnés, alors utilisez-le comme un guide et à vos risques et périls.
Ce que j'ai trouvé utile est le composant (commercial) [ShellBrowser] (http://www.jam-software.com/shellbrowser_net/?language=EN). –