Chú ý: bài dài với rất nhiều mã.
Khi bạn điều hướng điều khiển trình duyệt web vào thư mục hệ thống tệp, điều khiển trình duyệt web sẽ lưu trữ cửa sổ chế độ xem trình duyệt mà lưu trữ chế độ xem danh sách trình khám phá. Trong thực tế, điều này hoàn toàn giống với tiến trình Explorer cũng như các hộp thoại tập tin và Internet Explorer. Cửa sổ trình bao này không phải là một điều khiển nên không có phương thức nào có thể được gọi trên nó hoặc các sự kiện có thể được đăng ký nhưng nó có thể nhận được các thông điệp cửa sổ và nó có thể được phân loại phụ.
Nó chỉ ra rằng một phần của câu hỏi của bạn đối phó với thiết lập chế độ xem để chi tiết tự động thực sự là khá dễ dàng. Trong sự kiện điều hướng của trình duyệt điều khiển trình duyệt web của bạn, chỉ cần tìm tay cầm đến cửa sổ xem vỏ và gửi cho nó một thông điệp WM_COMMAND với một hằng số vỏ cụ thể (SHVIEW_REPORT). Đây là một lệnh không có giấy tờ nhưng nó được hỗ trợ trên tất cả các nền tảng Windows lên đến và bao gồm Windows 2008 và gần như chắc chắn sẽ có trên Windows 7.Một số mã để thêm vào hình thức trình duyệt web của bạn chứng tỏ điều này:
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;
}
Mỗi lần trình duyệt web điều hướng tới một cửa sổ mới (kể cả khi một thư mục được mở từ bên trong xem thám hiểm) một cửa sổ xem vỏ mới được tạo nên thư phải được gửi lại đến cửa sổ mới trong mọi sự kiện được điều hướng.
Đối với phần thứ hai của câu hỏi bạn muốn nhận sự kiện từ chế độ xem danh sách người khám phá. Điều này hơi khó hơn một chút so với phần đầu tiên. Để làm điều này, bạn sẽ cần phải sub-class cửa sổ xem danh sách và sau đó theo dõi các cửa sổ tin nhắn cho những người mà bạn quan tâm (chẳng hạn như WM_LBUTTONDBLCLK). Để sub-class một cửa sổ, bạn sẽ cần phải tạo lớp của riêng bạn bắt nguồn từ lớp NativeWindow và gán nó cho handle của cửa sổ mà bạn cần theo dõi. Sau đó, bạn có thể ghi đè lên quy trình Cửa sổ của nó và xử lý các thông báo khác nhau như bạn muốn. Dưới đây là một ví dụ về việc tạo một sự kiện nhấp đúp - nó tương đối đơn giản nhưng để có được quyền truy cập rộng rãi vào chế độ xem danh sách nhà thám hiểm có thể liên quan đến nhiều công việc hơn bạn sẵn sàng làm.
Thêm vào form của bạn:
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);
}
và hai dòng này để xử lý lèo lái sự kiện (ngay sau khi SendMessage):
m_Explorer = new ExplorerListView(m_ShellView);
m_Explorer.ItemExecuted += OnExplorerItemExecuted;
Sau đó, thêm các lớp học sau:
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;
}
}
Điều này sẽ cung cấp cho bạn ý tưởng về những gì bạn cần làm. Nếu bạn muốn nhiều hơn các sự kiện khá đơn giản, bạn có thể muốn tìm một điều khiển thay thế, mặc dù từ những gì tôi thấy trong các lĩnh vực miễn phí và chi phí thấp, có một số điều khiển khá phong nha nhưng tất cả đều có một số kỳ quặc và sẽ không cung cấp cho nhà thám hiểm liền mạch kinh nghiệm.
Hãy nhớ mã này được đặt cùng nhau một cách nhanh chóng mà không cần xử lý lỗi hoặc nhận xét và bỏ qua một số vấn đề như nhiều mục đã chọn, vì vậy hãy sử dụng nó làm phương châm và có nguy cơ của riêng bạn.
Những gì tôi thấy hữu ích là (thương mại) [thành phần ShellBrowser] (http://www.jam-software.com/shellbrowser_net/?language=EN). –