Search code examples
c#.netvb.netsavefiledialog

Really Custom OpenFileDialog .NET


I want to have an custom OpenFileDialog form within my project where I can add/remove buttons and customize whatever I want like a normal form. This is mainly so that it fits into the theme I am using, additionally, I can add custom buttons. Is there any tutorials on how I could construct my own? Are there any pre-existing projects I can use straight out of the download?


Solution

  • I hope that will fit your requirements:

    Result

    You will need one TreeView and an ImageList

    Code

    You will need System.Runtime.InteropServices;

    And following code to get the associated icon from the path:

        [StructLayout(LayoutKind.Sequential)]
        public struct SHFILEINFO
        {
            public IntPtr hIcon;
            public IntPtr iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };
    
        class Win32
        {
            public const uint SHGFI_ICON = 0x100;
            public const uint SHGFI_LARGEICON = 0x0;    // 'Large icon
            public const uint SHGFI_SMALLICON = 0x1;    // 'Small icon
    
            [DllImport("shell32.dll")]
            public static extern IntPtr SHGetFileInfo(string pszPath,
                                        uint dwFileAttributes,
                                        ref SHFILEINFO psfi,
                                        uint cbSizeFileInfo,
                                        uint uFlags);
        }
    
        private int GetIconOfFile_Folder(string Path)
        {
            IntPtr hImgSmall;    //the handle to the system image list
            IntPtr hImgLarge;    //the handle to the system image list
            string fName;        // 'the file name to get icon from
            SHFILEINFO shinfo = new SHFILEINFO();
    
            //Use this to get the small Icon
            hImgSmall = Win32.SHGetFileInfo(Path, 0, ref shinfo,
                                           (uint)Marshal.SizeOf(shinfo),
                                            Win32.SHGFI_ICON |
                                            Win32.SHGFI_SMALLICON);
    
            //Use this to get the large Icon
            //hImgLarge = SHGetFileInfo(fName, 0,
            //ref shinfo, (uint)Marshal.SizeOf(shinfo),
            //Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
            //The icon is returned in the hIcon member of the shinfo
            //struct
            System.Drawing.Icon myIcon =
                   System.Drawing.Icon.FromHandle(shinfo.hIcon);
    
            imageList1.Images.Add(myIcon);
    
            return imageList1.Images.Count - 1;
        }
    

    Use following Method to Get all your Drives (best place it in your constructor/Form_Load):

        private void GetAllDrives()
        {
            DriveInfo[] drives = DriveInfo.GetDrives();
            foreach (var drive in drives)
            {
                TreeNode rootTreeNode = new TreeNode();
                rootTreeNode.Text = drive.Name;
                rootTreeNode.Tag = drive.Name;
                rootTreeNode.ImageIndex = GetIconOfFile_Folder(drive.Name);
                rootTreeNode.SelectedImageIndex = rootTreeNode.ImageIndex;
                rootTreeNode.Nodes.Add(" "); //Placeholder to enable expanding (+)
                treeView1.Nodes.Add(rootTreeNode);
            }
        }
    

    Then you will need an EventHandler for the Expand-Event, which will call the method GetFilesAndFolder()

        private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            e.Node.Nodes.Clear();
            GetFilesAndFolder(e.Node, (string)e.Node.Tag);
        }
    
        private void GetFilesAndFolder(TreeNode tn, string Path)
        {
            try
            {
                string[] Directories = Directory.GetDirectories(Path);
                string[] Files = Directory.GetFiles(Path);
    
                foreach (string dir in Directories)
                {
                    TreeNode dirTreeNode = new TreeNode();
                    dirTreeNode.Tag = dir;
                    dirTreeNode.Text = new DirectoryInfo(dir).Name;
                    dirTreeNode.ImageIndex = GetIconOfFile_Folder(dir);
                    dirTreeNode.SelectedImageIndex = dirTreeNode.ImageIndex;
                    dirTreeNode.Nodes.Add(" ");
                    tn.Nodes.Add(dirTreeNode);
                }
    
                foreach (string file in Files)
                {
                    TreeNode fileTreeNode = new TreeNode();
                    fileTreeNode.Tag = file;
                    fileTreeNode.Text = new FileInfo(file).Name;
                    fileTreeNode.ImageIndex = GetIconOfFile_Folder(file);
                    fileTreeNode.SelectedImageIndex = fileTreeNode.ImageIndex;
                    tn.Nodes.Add(fileTreeNode);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
    

    Finally I have created an EventHandler for the NodeDoubleClick-Event in the TreeView:

        private void treeView1_NodeMouseDoubleClick(object sender,                 TreeNodeMouseClickEventArgs e)
        {
            if (CheckIfPathIsFile(e.Node.Tag.ToString()) == true) //If the Tag (Path) is a File
            {
                //Do something with the Path (close this Form + return Path)
            }
        }
    
        private bool CheckIfPathIsFile(string Path)
        {
            // get the file attributes for file or directory
            FileAttributes attr = File.GetAttributes(Path);
    
            //detect whether its a directory or file
            if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
                return false;
            else
                return true;
        }