Customizing Openfiledialog

Customizing OpenFileDialog

Yes, that's possible, I did the same kind of customization with SaveFileDialog successfully and it's pretty interesting.

Follow the following links:

http://www.codeproject.com/KB/dialog/OpenFileDialogEx.aspx

http://www.codeproject.com/KB/cs/getsavefilename.aspx

http://www.codeproject.com/KB/dialog/CustomizeFileDialog.aspx

Also my own questions too will help you:

Change default arrangement of Save and Cancel buttons in SaveFileDialog

How to stop overwriteprompt when creating SaveFileDialog using GetSaveFileName

You have to use the WinAPI for this and you need to write the ShowDialog method in your own calling the GetOpenFileName windows function inside it, instead of calling .net's OpenFileDialog. The GetOpenFileName will create the windows OpenFileDialog. (Refer to http://msdn.microsoft.com/en-us/library/ms646927%28v=vs.85%29.aspx). This together with writing the HookProc procedure and catching events such as WM_INITDIALOG, CDN_INITDONE inside it will help you do what you want.

To add radio buttons etc., you have to call the windows functions such as CreateWindowEx and SendMessage....

The 2nd link has the exact direction to the customization...

Ask for any clarifications...

Really Custom OpenFileDialog .NET

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

Customizing OpenFileDialog to modify button text

If you are using this version of the pack, then I don't think there is an easy out-of-the-box soloution. It can be done, but it requires a bit of Reflection to work (if someone found a simpler way, please do share).

First, you have to reference System.Windows.Forms asembly in your project (if you don't have it already).

Then, you mock-use it at least once, so the method GetReferencedAssemblies() returns it (again, if you use it anyway, you can skip this step), the following line of code will suffice:

Form f=null;

Now, this is a class with a few methods to make the necessary reflection easier:

public class MyReflector
{
string myNamespace;
Assembly myAssembly;
public MyReflector(string assemblyName, string namespaceName)
{
myNamespace = namespaceName;
myAssembly = null;
var alist=Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (AssemblyName aN in alist)
{
if (aN.FullName.StartsWith(assemblyName))
{
myAssembly = Assembly.Load(aN);
break;
}
}
}
public Type GetType(string typeName)
{
Type type = null;
string[] names = typeName.Split('.');

if (names.Length > 0)
type = myAssembly.GetType(myNamespace + "." + names[0]);

for (int i = 1; i < names.Length; ++i)
{
type = type.GetNestedType(names[i], BindingFlags.NonPublic);
}
return type;
}

public object Call(Type type, object obj, string func, object[] parameters)
{
MethodInfo methInfo = type.GetMethod(func, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return methInfo.Invoke(obj, parameters);
}

public object GetField(Type type, object obj, string field)
{
FieldInfo fieldInfo = type.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return fieldInfo.GetValue(obj);
}
}

Finally, the code to set the button's text.

    CommonOpenFileDialog ofp = new CommonOpenFileDialog();
ofp.IsFolderPicker = true;

// In the CommonFileDialog in WindowsAPICodePack, there is a nativeDialog field of type IFileDialog
// get it first and check if it's not null:
var r1 = new MyReflector("Microsoft.WindowsAPICodePack", "Microsoft.WindowsAPICodePack");
Type typeCommonFileDialog = typeof(CommonFileDialog);
object nativeDialog = r1.GetField(typeCommonFileDialog, ofp, "nativeDialog");
if (nativeDialog == null)
{
// if nativeDialog was null, initialize it:
r1.Call(ofp.GetType(), ofp, "InitializeNativeFileDialog", new object[]{});
nativeDialog = r1.Call(ofp.GetType(), ofp, "GetNativeFileDialog", new object[] { });
}

// call SetOkButtonLabel method on nativeDialog object
var r2 = new MyReflector("System.Windows.Forms", "System.Windows.Forms");
Type typeIFileDialog = r2.GetType("FileDialogNative.IFileDialog");
r2.Call(typeIFileDialog, nativeDialog, "SetOkButtonLabel",new object[] { "Save" });

ofp.ShowDialog();

EXPLANATION:

In WindowsAPICodePack, CommonOpenFileDialog is a subclass of CommonFileDialog class. In the CommonFileDialog, there is a nativeDialog field of type IFileDialog (the type IFileDialog also isn't public). You can use it to set the text of a button. Sadly, it's private. It is also not initialized after calling just the constructor (some methods initialize it though, so you have to check if it's null at the start). IFileDialog has an internal method SetOkButtonLabel. That's what you need.



Related Topics



Leave a reply



Submit