浏览器扩展文件夹
介绍 你曾经试图改变什么c#在浏览器的文件夹对话框? 在这篇文章中,我将向您展示如何更改对话框。例如,如果我们想禁用“让新文件夹”按钮选择每次CD驱动器吗?或者如果我们希望用户选择只有从现有的文件夹,除了一个文件夹也可以使子文件夹吗? 背景 net有FolderBrowserDialog控制,基本上,SHBrowseForFolder的Win32函数的包装器。唯一的问题是,这个类是一个封闭的类,所以我们不能来源于它并添加功能。这种控制不提供任何事件我们可以注册和执行代码。基本上,如果你满意控制,那么你就好了。但是一旦你需要做一个小变化,你必须找出控制确实有效。 在本文中,我们将看到的,一步一步,我们如何禁用“让新文件夹”每次CD驱动器被选中。 为了实现我们的目标,我们必须解决两个主要问题: 让控制火灾事件每次选择改变。 禁用按钮。 使用的代码 我们要做的第一件事是创建一个ExtendedFolderBrowser类。这个类将举行一个私人类,InternalFolderBrowser,来自CommonDialog。InternalFolderBrowser基本上是浏览器文件夹对话框的实现,但这将使我们能够实现扩展功能,在父类中添加新插件。当CommonDialog派生的类,我们需要实现两个方法:重置和Rundialog。隐藏,收缩,复制Code
private class InternalFolderBrowser : CommonDialog { private string m_selectedPath = null; private Environment.SpecialFolder m_rootFolder; public event EventHandler SelectedFolderChanged; private string m_descriptionText = String.Empty; public override void Reset() { m_rootFolder = Environment.SpecialFolder.Desktop; m_selectedPath = string.Empty; } protected override bool RunDialog(System.IntPtr hwndOwner) { IntPtr ptr1 = IntPtr.Zero; bool flag1 = false; Win32API.SHGetSpecialFolderLocation(hwndOwner, (int)m_rootFolder, ref ptr1); if (ptr1 == IntPtr.Zero) { Win32API.SHGetSpecialFolderLocation(hwndOwner, 0, ref ptr1); if (ptr1 == IntPtr.Zero) { throw new Exception("FolderBrowserDialogNoRootFolder"); } } //Initialize the OLE to current thread. Application.OleRequired(); IntPtr ptr2 = IntPtr.Zero; try { Win32API.BROWSEINFO browseinfo1 = new Win32API.BROWSEINFO(); IntPtr ptr3 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize)); IntPtr ptr4 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize)); Win32API.BrowseCallbackProc proc1 = new Win32API.BrowseCallbackProc( this.FolderBrowserDialog_BrowseCallbackProc); browseinfo1.pidlRoot = ptr1; browseinfo1.hwndOwner = hwndOwner; browseinfo1.pszDisplayName = ptr3; browseinfo1.lpszTitle = m_descriptionText; browseinfo1.ulFlags = 0x40; browseinfo1.lpfn = proc1; browseinfo1.lParam = IntPtr.Zero; browseinfo1.iImage = 0; ptr2 = Win32API.SHBrowseForFolder(browseinfo1); string s = Marshal.PtrToStringAuto(ptr3); if (ptr2 != IntPtr.Zero) { Win32API.SHGetPathFromIDList(ptr2, ptr4); this.m_selectedPath = Marshal.PtrToStringAuto(ptr4); Marshal.FreeHGlobal(ptr4); Marshal.FreeHGlobal(ptr3); flag1 = true; } } finally { Win32API.IMalloc malloc1 = GetSHMalloc(); malloc1.Free(ptr1); if (ptr2 != IntPtr.Zero) { malloc1.Free(ptr2); } } return flag1; }
当我们创建BROWSEINFO结构,向函数传递一个委托,呼吁每一个变化的控制:隐藏,收缩,复制Code
private int FolderBrowserDialog_BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData) { switch (msg) { case Win32API.BFFM_INITIALIZED: if (m_selectedPath != string.Empty) { Win32API.SendMessage(new HandleRef(null, hwnd), 0x467, 1, m_selectedPath); } break; case Win32API.BFFM_SELCHANGED: //Selction Changed { IntPtr ptr1 = lParam; if (ptr1 != IntPtr.Zero) { IntPtr ptr2 = Marshal.AllocHGlobal((int) (260 * Marshal.SystemDefaultCharSize)); bool flag1 = Win32API.SHGetPathFromIDList(ptr1, ptr2); m_selectedPath = Marshal.PtrToStringAuto(ptr2); //Fire Event if(SelectedFolderChanged != null) { SelectedFolderChanged(this,null); } Marshal.FreeHGlobal(ptr2); Win32API.SendMessage2(new HandleRef(null, hwnd), 0x465, 0, flag1 ? 1 : 0); } break; } } return 0; }
每一次选择改变,我们将通知BFFM_SELCHANGED消息。一旦我们收到消息,我们将火灾事件我们的父类,ExtendedFolderBrowser,也会得到通知。 我们应该做的最后一件事就是注册事件的内部类和禁用按钮。 在选择发生改变时,我们将执行一个利用CheckState方法:隐藏,复制Code
/// <summary> /// Check if we should disable the 'Make New Folder' button /// </summary> private void CheckState() { if(m_ShowNewButtonHandler != null) { if(m_ShowNewButtonHandler(SelectedPath)) { //Disabel the button UpdateButtonState(GetButtonHandle(IntPtr.Zero), false); } else { //Enable the button UpdateButtonState(GetButtonHandle(IntPtr.Zero),true); } } }
m_ShowNewButtonHandler代表用户函数将检查我们是否应该根据当前选择禁用按钮。当客户端创建一个对话框,它将通过一项委托给它的功能做出决定关于按钮的状态。 改变按钮的状态,我们只是使用EnableWindow API:隐藏,复制Code
private void UpdateButtonState(IntPtr handle, bool state) { if(handle != IntPtr.Zero) { Win32API.EnableWindow(handle,state); } }
剩下要做最后一个棘手的事情是让按钮的处理。处理,我们将寻找类名“32770 #”,这是浏览器文件夹对话框的类。问题是这门课的名字不是独一无二的,所以我们必须让另一个检查是否这个处理我们发现实际上是来自同一个线程正在运行。如果它是来自同一线程,宾果!,我们发现处理程序对话框控件,否则我们将继续搜索。 一旦我们找到了对话框句柄,剩下是返回的第一个孩子处理按钮的类型。这将是句柄的新文件夹”按钮。隐藏,收缩,复制Code
private bool isFromTheSameThread(IntPtr windowHandle) { //Get the thread that running given handler IntPtr activeThreadID = Win32API.GetWindowThreadProcessId(windowHandle, IntPtr.Zero); //Get current thread int currentThread = AppDomain.GetCurrentThreadId(); return (currentThread == activeThreadID.ToInt32()); } private IntPtr GetButtonHandle(IntPtr handle) { //First time if(handle == IntPtr.Zero) { //Get Handle for class with name "#32770" IntPtr parent = Win32API.FindWindow(BROWSE_FOR_FOLDER_CLASS_NAME,null); //If the window we found is in the same thread we are running //then it is The 'Browse For Folder' Dialog, otherwise keep searching if(!isFromTheSameThread(parent)) { //Keep searching from this point return GetButtonHandle(parent); } else { return Win32API.FindWindowEx(parent,IntPtr.Zero,"Button", null); } } else { //Find next window IntPtr parent = Win32API.FindWindowEx(IntPtr.Zero, handle,BROWSE_FOR_FOLDER_CLASS_NAME, null); if(!isFromTheSameThread(parent)) { return GetButtonHandle(parent); } else { //We found the 'Browse For Folder' Dialog handler. //Lets return the child handler of 'Maker new Folder' button return Win32API.FindWindowEx(parent,IntPtr.Zero,"Button", null); } } }
最后我想向大家展示的是如何使用这个控制:隐藏,复制Code
ExtendedFolderBrowser m_ExtendedFolderBrowser = new ExtendedFolderBrowser(); m_ExtendedFolderBrowser.Description = "Folder Browser"; //Create a hanlder to a function which will check //if to show the 'Make New Button' button ShowNewButtonHandler handler = new ShowNewButtonHandler(IsCDDrive); //Set the handler m_ExtendedFolderBrowser.SetNewFolderButtonCondition = handler; m_ExtendedFolderBrowser.ShowDialog();
本文转载于:http://www.diyabc.com/frontweb/news6633.html