gpt4 book ai didi

c# - 在 Windows 窗体应用程序表单中嵌入文件资源管理器实例

转载 作者:可可西里 更新时间:2023-11-01 08:19:33 25 4
gpt4 key购买 nike

我的(C#、.NET 3.5)应用程序生成文件,除了引发可以捕获和响应的事件外,我还想以一种形式向用户显示目标文件夹。文件列表以与其他信息相同的形式显示。

我正在使用 WebBrowser 控件 (System.Windows.Forms.WebBrowser) 的一个实例,然后导航到该文件夹​​。这显示了资源管理器窗口的一些默认 View ,左侧是文件摘要面板,文件位于“平铺”(大图标和文本) View 中。

例如,

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

我想隐藏面板并在详细信息 View 中查看文件列表。用户可以通过右键单击上下文菜单访问它,但我希望它自动出现。

我宁愿不必构建自己的 TreeView、DataGridView 或其他任何东西; WebBrowser 控件会“免费”执行所有更新和重新排序等操作。

有没有更好的方法?要使用不同的控件还是要传递给控件的一些额外参数?

如果我可以捕获事件(例如,文件被选择/重命名/双击等),那就更好了!

最佳答案

警告:包含大量代码的长篇文章。

当您将 Web 浏览器控件导航到文件系统文件夹时,Web 浏览器控件会托管一个 shell View 窗口,而该窗口又会托管资源管理器 ListView 。事实上,这与 Explorer 进程以及文件对话框和 Internet Explorer 所做的完全相同。这个 shell 窗口不是一个控件,所以没有可以调用它的方法或可以订阅的事件,但它可以接收窗口消息并且可以被子类化。

事实证明,您的问题中涉及自动将 View 设置为“详细信息”的部分实际上非常简单。在您的 Web 浏览器控件的 Navigated 事件中,只需找到 shell View 窗口的句柄并向它发送一个带有特定 shell 常量 (SHVIEW_REPORT) 的 WM_COMMAND 消息。这是一个未记录的命令,但它在所有 Windows 平台上受支持,包括 Windows 2008,并且几乎肯定会在 Windows 7 上。添加到 Web 浏览器表单的一些代码演示了这一点:

    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;
}

每次 Web 浏览器导航到新窗口(包括从资源管理器 View 中打开文件夹时)都会创建一个新的 shell View 窗口,因此必须在每个 Navigated 事件中将消息重新发送到新窗口。

对于问题的第二部分,您希望从资源管理器 ListView 接收事件。这比第一部分难很多。为此,您需要对 ListView 窗口进行子类化,然后监视您感兴趣的窗口消息(例如 WM_LBUTTONDBLCLK)。为了对窗口进行子类化,您需要创建自己的从 NativeWindow 类派生的类,并为其分配您需要监视的窗口的句柄。然后您可以覆盖它的窗口过程并按您的意愿处理各种消息。下面是创建双击事件的示例 - 它相对简单,但要广泛访问资源管理器 ListView 可能涉及比您愿意做的更多的工作。

将此添加到您的表单中:

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

和导航事件处理程序的这两行(在 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;
}
}

这应该让您了解您需要做什么。如果你想要的不仅仅是相当简单的事件,你可能想要寻找一个替代控件,尽管从我在免费和低成本区域看到的情况来看,有一些相当不错的控件,但它们都有一些怪癖并且不会提供无缝的浏览器经验。

请记住,这段代码是在没有错误处理或注释的情况下快速组合在一起的,并且忽略了多个问题(例如多个选定项目),因此请将其用作指南并自行承担风险。

关于c# - 在 Windows 窗体应用程序表单中嵌入文件资源管理器实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/542378/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com