Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Extend OpenFileDialog and SaveFileDialog the easy way

, 22 Mar 2012
Customize OpenFileDialog and SaveFileDialog using a User Control
CustomFileDialog_old.zip
CustomFileDialog
Properties
Settings.settings
FileDlgExtenders
Properties
CustomFileDialog_src2.zip
VB_Code
FileDlgExtenders
CSharp_Code
FileDlgExtenders
Properties
Properties
My Project
Settings.settings
My Project
Settings.settings
bin
release
bin
Debug
Release
obj
Debug
DesignTimeResolveAssemblyReferencesInput.cache
Refactor
FileDlgExtenders.dll
TempPE
Release
Refactor
TempPE
CustomFileDialog_src_old.zip
C__Projects_CustomFileDialog_src2.zip
Settings.settings
Settings.settings
DesignTimeResolveAssemblyReferencesInput.cache
FileDlgExtenders.dll
CustomFileDialog_src_old.zip
C__Projects_release2.zip
release2.zip
//  Copyright (c) 2006, Gustavo Franco
//  Copyright � Decebal Mihailescu 2007-2010

//  Email:  gustavo_franco@hotmail.com
//  All rights reserved.

//  Redistribution and use in source and binary forms, with or without modification, 
//  are permitted provided that the following conditions are met:

//  Redistributions of source code must retain the above copyright notice, 
//  this list of conditions and the following disclaimer. 
//  Redistributions in binary form must reproduce the above copyright notice, 
//  this list of conditions and the following disclaimer in the documentation 
//  and/or other materials provided with the distribution. 

//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE. IT CAN BE DISTRIBUTED FREE OF CHARGE AS LONG AS THIS HEADER 
//  REMAINS UNCHANGED.

using System;
using System.IO;
using System.Text;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using Win32Types;

namespace FileDialogExtenders
{
    #region Base class

    public partial class FileDialogControlBase : UserControl//, IMessageFilter
    {
        #region Delegates
        public delegate void PathChangedEventHandler(IWin32Window sender, string filePath);
        public delegate void FilterChangedEventHandler(IWin32Window sender, int index);
        #endregion

        #region Events
        //for weird reasons the designer wants the events public not protected    
        [Category("FileDialogExtenders")]
        public event PathChangedEventHandler EventFileNameChanged;
        [Category("FileDialogExtenders")]
        public event PathChangedEventHandler EventFolderNameChanged;
        [Category("FileDialogExtenders")]
        public event FilterChangedEventHandler EventFilterChanged;
        [Category("FileDialogExtenders")]
        public event CancelEventHandler EventClosingDialog;
        #endregion

        #region Constants Declaration
        private const SetWindowPosFlags UFLAGSHIDE =
            SetWindowPosFlags.SWP_NOACTIVATE |
            SetWindowPosFlags.SWP_NOOWNERZORDER |
            SetWindowPosFlags.SWP_NOMOVE |
            SetWindowPosFlags.SWP_NOSIZE |
            SetWindowPosFlags.SWP_HIDEWINDOW;
        #endregion

        #region Variables Declaration
        System.Windows.Forms.FileDialog _MSdialog;
        NativeWindow _dlgWrapper;
        private AddonWindowLocation _StartLocation = AddonWindowLocation.Right;
        private FolderViewMode _DefaultViewMode = FolderViewMode.Default;
        IntPtr _hFileDialogHandle = IntPtr.Zero;
        FileDialogType _FileDlgType;
        string _InitialDirectory = string.Empty;
        string _Filter = "All files (*.*)|*.*";
        string _DefaultExt = "jpg";
        string _FileName = string.Empty;
        string _Caption = "Save";
        string _OKCaption = "&Open";
        int _FilterIndex = 1;
        bool _AddExtension = true;
        bool _CheckFileExists = true;
        bool _EnableOkBtn = true;
        bool _DereferenceLinks = true;
        bool _ShowHelp;
        RECT _OpenDialogWindowRect = new RECT();
        IntPtr _hOKButton = IntPtr.Zero;
        private bool _hasRunInitMSDialog;
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        IntPtr _hListViewPtr;

        #endregion

        #region Constructors
        public FileDialogControlBase()
        {
            InitializeComponent();
        }
        #endregion

        #region Properties
        static uint _originalDlgHeight, _originalDlgWidth;

        internal static uint OriginalDlgWidth
        {
            get { return FileDialogControlBase._originalDlgWidth; }
            set { FileDialogControlBase._originalDlgWidth = value; }
        }

        internal static uint OriginalDlgHeight
        {
            get { return FileDialogControlBase._originalDlgHeight; }
            set { FileDialogControlBase._originalDlgHeight = value; }
        }

        [Browsable(false)]
        public string[] FileDlgFileNames
        {
            get { return DesignMode ? null : MSDialog.FileNames; }
        }

        [Browsable(false)]
        public FileDialog MSDialog
        {
            set { _MSdialog = value; }
            get { return _MSdialog; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(AddonWindowLocation.Right)]
        public AddonWindowLocation FileDlgStartLocation
        {
            get { return _StartLocation; }
            set
            {
                _StartLocation = value;
                if (DesignMode)
                {
                    this.Refresh();
                }
            }
        }

        Size _OriginalCtrlSize;
        internal Size OriginalCtrlSize
        {
            get { return _OriginalCtrlSize; }
            set
            {
                _OriginalCtrlSize = value;
            }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(FolderViewMode.Default)]
        public FolderViewMode FileDlgDefaultViewMode
        {
            get { return _DefaultViewMode; }
            set { _DefaultViewMode = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(FileDialogType.OpenFileDlg)]
        public FileDialogType FileDlgType
        {
            get { return _FileDlgType; }
            set { _FileDlgType = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue("")]
        public string FileDlgInitialDirectory
        {
            get { return DesignMode ? _InitialDirectory : MSDialog.InitialDirectory; }
            set
            {
                _InitialDirectory = value;
                if (!DesignMode && MSDialog != null)
                    MSDialog.InitialDirectory = value;
            }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue("")]
        public string FileDlgFileName
        {
            get { return DesignMode ? _FileName : MSDialog.FileName; }
            set { _FileName = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue("")]
        public string FileDlgCaption
        {
            get { return _Caption; }
            set { _Caption = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue("&Open")]
        public string FileDlgOkCaption
        {
            get { return _OKCaption; }
            set { _OKCaption = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue("jpg")]
        public string FileDlgDefaultExt
        {
            get { return DesignMode ? _DefaultExt : MSDialog.DefaultExt; }
            set { _DefaultExt = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue("All files (*.*)|*.*")]
        public string FileDlgFilter
        {
            get { return DesignMode ? _Filter : MSDialog.Filter; }
            set { _Filter = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(1)]
        public int FileDlgFilterIndex
        {
            get { return DesignMode ? _FilterIndex : MSDialog.FilterIndex; }
            set { _FilterIndex = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(true)]
        public bool FileDlgAddExtension
        {
            get { return DesignMode ? _AddExtension : MSDialog.AddExtension; }
            set { _AddExtension = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(true)]
        public bool FileDlgEnableOkBtn
        {
            get { return _EnableOkBtn; }
            set
            {
                _EnableOkBtn = value;
                if (!DesignMode && MSDialog != null && _hOKButton != IntPtr.Zero)
                    Win32Types.NativeMethods.EnableWindow(_hOKButton, _EnableOkBtn);
            }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(true)]
        public bool FileDlgCheckFileExists
        {
            get { return DesignMode ? _CheckFileExists : MSDialog.CheckFileExists; }
            set
            { _CheckFileExists = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(false)]
        public bool FileDlgShowHelp
        {
            get { return DesignMode ? _ShowHelp : MSDialog.ShowHelp; }
            set { _ShowHelp = value; }
        }

        [Category("FileDialogExtenders")]
        [DefaultValue(true)]
        public bool FileDlgDereferenceLinks
        {
            get { return DesignMode ? _DereferenceLinks : MSDialog.DereferenceLinks; }
            set { _DereferenceLinks = value; }
        }
        #endregion

        #region Virtuals
        //this is a hidden child window dor the whole dialog
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!DesignMode)
            {
                if (MSDialog != null)
                {
                    MSDialog.FileOk += new CancelEventHandler(FileDialogControlBase_ClosingDialog);
                    MSDialog.Disposed += new EventHandler(FileDialogControlBase_DialogDisposed);
                    MSDialog.HelpRequest += new EventHandler(FileDialogControlBase_HelpRequest);
                    FileDlgEnableOkBtn = _EnableOkBtn;//that's design time value
                    NativeMethods.SetWindowText(new HandleRef(_dlgWrapper,_dlgWrapper.Handle), _Caption);
                    //will work only for open dialog, save dialog will be overriden internally by windows
                    NativeMethods.SetWindowText(new HandleRef(this,_hOKButton), _OKCaption);//SetDlgItemText fails too 
                    //bool res = NativeMethods.SetDlgItemText(NativeMethods.GetParent(Handle), (int)ControlsId.ButtonOk, FileDlgOkCaption);
                }
            }
        }

        public void SortViewByColumn(int index)
        {
            try
            {
                //handle of the "defView" --> container of the listView  
                IntPtr hWndWin = NativeMethods.FindWindowEx(_dlgWrapper.Handle, IntPtr.Zero, "SHELLDLL_DefView", "");

                if (hWndWin != IntPtr.Zero)
                {
                    //change to details view
                    NativeMethods.SendMessage(new HandleRef(this, hWndWin), (int)Msg.WM_COMMAND, (IntPtr)(int)DefaultViewType.Details, IntPtr.Zero);

                    #region  sort by date
                    int HDN_FIRST = (-300);
                    int HDN_ITEMCLICKW = (HDN_FIRST - 22);

                    //get the ListView//s hWnd
                    IntPtr hWndLV = NativeMethods.FindWindowEx(hWndWin, IntPtr.Zero, "SysListView32", IntPtr.Zero);
                    //get the ColumnHeaders hWnd
                    IntPtr hWndColHd = NativeMethods.FindWindowEx(hWndLV, IntPtr.Zero, "SysHeader32", IntPtr.Zero);

                    //now click on column 3 to sort for date
                    NMHEADER NMH = new NMHEADER();
                    NMH.hdr.hwndFrom = hWndColHd;
                    NMH.hdr.code = (uint)HDN_ITEMCLICKW;
                    NMH.iItem = index;
                    NMH.iButton = 0;

                    // Initialize unmanged memory to hold the struct.
                    IntPtr ptrNMH = Marshal.AllocHGlobal(Marshal.SizeOf(NMH));
                    try
                    {

                        // Copy the struct to unmanaged memory.
                        Marshal.StructureToPtr(NMH, ptrNMH, false);

                        NativeMethods.SendMessage(new HandleRef(this, hWndLV), (uint)Msg.WM_NOTIFY, IntPtr.Zero, ptrNMH);
                        //click again for descending order = newest files first
                        NativeMethods.SendMessage(new HandleRef(this, hWndLV), (uint)Msg.WM_NOTIFY, IntPtr.Zero, ptrNMH);
                    }
                    finally
                    {
                        // Free the unmanaged memory.
                        Marshal.FreeHGlobal(ptrNMH);
                    }



                    ////if wanted give the dialog a larger size here
                    //If DialogXSize > 0 And DialogYSize > 0 Then
                    //   SetWindowPos hWndDlg, 0&, 0&, 0&, DialogXSize, DialogYSize, 0&
                    //End If
                    //}
                    #endregion
                }
            }
            catch 
            {
            }
        } 
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (IsDisposed)
                return;
            if (MSDialog != null)
            {
                MSDialog.FileOk -= new CancelEventHandler(FileDialogControlBase_ClosingDialog);
                MSDialog.Disposed -= new EventHandler(FileDialogControlBase_DialogDisposed);
                MSDialog.HelpRequest -= new EventHandler(FileDialogControlBase_HelpRequest);
                MSDialog.Dispose();
                MSDialog = null;
            }
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        public virtual void OnFileNameChanged(IWin32Window sender, string fileName)
        {
            if (EventFileNameChanged != null)
                EventFileNameChanged(sender, fileName);
        }

        public void OnFolderNameChanged(IWin32Window sender, string folderName)
        {
            if (EventFolderNameChanged != null)
                EventFolderNameChanged(sender, folderName);
            UpdateListView();
        }

        private void UpdateListView()
        {
            _hListViewPtr = Win32Types.NativeMethods.GetDlgItem(_hFileDialogHandle, (int)ControlsId.DefaultView);
            if (FileDlgDefaultViewMode != FolderViewMode.Default && _hFileDialogHandle != IntPtr.Zero)
            {
                NativeMethods.SendMessage(new HandleRef(this, _hListViewPtr), (int)Msg.WM_COMMAND, (IntPtr)(int)FileDlgDefaultViewMode, IntPtr.Zero);
                if (FileDlgDefaultViewMode == FolderViewMode.Details || FileDlgDefaultViewMode == FolderViewMode.List)
                    SortViewByColumn(0);
            }
        }

        internal void OnFilterChanged(IWin32Window sender, int index)
        {
            if (EventFilterChanged != null)
                EventFilterChanged(sender, index);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (DesignMode)
            {
                Graphics gr = e.Graphics;
                {
                    HatchBrush hb = null;
                    Pen p = null;
                    try
                    {
                        switch (this.FileDlgStartLocation)
                        {
                            case AddonWindowLocation.Right:
                                hb = new System.Drawing.Drawing2D.HatchBrush(HatchStyle.NarrowHorizontal, Color.Black, Color.Red);
                                p = new Pen(hb, 5);
                                gr.DrawLine(p, 0, 0, 0, this.Height);
                                break;
                            case AddonWindowLocation.Bottom:
                                hb = new System.Drawing.Drawing2D.HatchBrush(HatchStyle.NarrowVertical, Color.Black, Color.Red);
                                p = new Pen(hb, 5);
                                gr.DrawLine(p, 0, 0, this.Width, 0);
                                break;
                            case AddonWindowLocation.BottomRight:
                            default:
                                hb = new System.Drawing.Drawing2D.HatchBrush(HatchStyle.Sphere, Color.Black, Color.Red);
                                p = new Pen(hb, 5);
                                gr.DrawLine(p, 0, 0, 4, 4);
                                break;
                        }
                    }
                    finally
                    {
                        if (p != null)
                            p.Dispose();
                        if (hb != null)
                            hb.Dispose();
                    }
                }
            }
            base.OnPaint(e);
        }


        #endregion

        #region Methods
        public DialogResult ShowDialog()
        {
            return ShowDialog(null);
        }
        protected virtual void OnPrepareMSDialog()
        {
            InitMSDialog();
        }
        private void InitMSDialog()
        {
            MSDialog.InitialDirectory = _InitialDirectory.Length == 0 ? Path.GetDirectoryName(Application.ExecutablePath) : _InitialDirectory;
            MSDialog.AddExtension = _AddExtension;
            MSDialog.Filter = _Filter;
            MSDialog.FilterIndex = _FilterIndex;
            MSDialog.CheckFileExists = _CheckFileExists;
            MSDialog.DefaultExt = _DefaultExt;
            MSDialog.FileName = _FileName;
            MSDialog.DereferenceLinks = _DereferenceLinks;
            MSDialog.ShowHelp = _ShowHelp;
            _hasRunInitMSDialog = true;
        }

        public DialogResult ShowDialog(IWin32Window owner)
        {
            DialogResult returnDialogResult = DialogResult.Cancel;
            if (this.IsDisposed)
                return returnDialogResult;
            if (owner == null || owner.Handle == IntPtr.Zero)
            {
                WindowWrapper wr = new WindowWrapper(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
                owner = wr;
            }
            OriginalCtrlSize = this.Size;
            _MSdialog = (FileDlgType == FileDialogType.OpenFileDlg)?new OpenFileDialog()as FileDialog:new SaveFileDialog() as FileDialog;
            _dlgWrapper = new WholeDialogWrapper(this);
            OnPrepareMSDialog();
            if (!_hasRunInitMSDialog)
                InitMSDialog();
            try
            {
                System.Reflection.PropertyInfo AutoUpgradeInfo = MSDialog.GetType().GetProperty("AutoUpgradeEnabled");
                if (AutoUpgradeInfo != null)
                    AutoUpgradeInfo.SetValue(MSDialog, false, null);
                returnDialogResult = _MSdialog.ShowDialog(owner);
            }
            // Sometimes if you open a animated .gif on the preview and the Form is closed, .Net class throw an exception
            // Lets ignore this exception and keep closing the form.
            catch (ObjectDisposedException)
            {
            }
            catch (Exception ex)
            {
                MessageBox.Show("unable to get the modal dialog handle", ex.Message);
            }
            return returnDialogResult;
        }

        internal DialogResult ShowDialogExt(FileDialog fdlg,IWin32Window owner)
        {
            DialogResult returnDialogResult = DialogResult.Cancel;
            if (this.IsDisposed)
                return returnDialogResult;
            if (owner == null || owner.Handle == IntPtr.Zero)
            {
                WindowWrapper wr = new WindowWrapper(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
                owner = wr;
            }
            OriginalCtrlSize = this.Size;
            MSDialog = fdlg;               
            _dlgWrapper = new WholeDialogWrapper(this);
            
            try
            {
                System.Reflection.PropertyInfo AutoUpgradeInfo = MSDialog.GetType().GetProperty("AutoUpgradeEnabled");
                if (AutoUpgradeInfo != null)
                    AutoUpgradeInfo.SetValue(MSDialog, false, null);
                returnDialogResult = _MSdialog.ShowDialog(owner);
            }
            // Sometimes if you open a animated .gif on the preview and the Form is closed, .Net class throw an exception
            // Lets ignore this exception and keep closing the form.
            catch (ObjectDisposedException)
            {
            }
            catch (Exception ex)
            {
                MessageBox.Show("unable to get the modal dialog handle", ex.Message);
            }
            return returnDialogResult;
        }
        #endregion


        #region event handlers
        void FileDialogControlBase_DialogDisposed(object sender, EventArgs e)
        {
            Dispose(true);
        }

        private void FileDialogControlBase_ClosingDialog(object sender, CancelEventArgs e)
        {
            if (EventClosingDialog != null)
            {
                EventClosingDialog(this, e);
            }
        }


        void FileDialogControlBase_HelpRequest(object sender, EventArgs e)
        {
            //this is a virtual call that should call the event in the subclass
            OnHelpRequested(new HelpEventArgs(new Point()));
        }

        #endregion
        #region helper types

        public class WindowWrapper : System.Windows.Forms.IWin32Window
        {
            public WindowWrapper(IntPtr handle)
            {
                _hwnd = handle;
            }

            public IntPtr Handle
            {
                get { return _hwnd; }
            }

            private IntPtr _hwnd;
        }
        #endregion
    }
    #endregion


}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

dmihailescu
Software Developer (Senior)
United States United States
Decebal Mihailescu is a software engineer with interest in .Net, C# and C++.

| Advertise | Privacy | Mobile
Web01 | 2.8.140718.1 | Last Updated 22 Mar 2012
Article Copyright 2007 by dmihailescu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid