[Net] [C #] [translation] custom file opening dialog box (source code + example)
Source: http://www.codeproject.com/KB/dialog/OpenFileDialogEx.aspx
Customizing openfiledialog in. Net by castortiu
- Download source code-300 KB
- Download example-286 KB
- Download the need to log on to [http://www.codeproject.com]
Introduction
A few days ago, I began to use my iconlib library to compile an icon editor program.
After creating the main window, I thought, "where should I start ?" Then I decided to create a menu with the "open" function and a preview function before opening the icon.
If you are reading this article, it is probably because you know that. Net has an openfiledialog class, but it cannot be customized. I wrote this control to allow you to add some features for the. NET openfiledialog class. You cannot customize the openfiledialog class because the class is declared as sealed, which means you cannot inherit it. If you go to the base class filedialog, this class allows you to inherit from it, but it has an internal abstract method "runfiledialog ". Because it is "internal" and "abstract", it is only allowed to inherit from the same assembly.
How many times do you need to place additional controls on the openfiledialog control ......
Search for. Net code. I found some code that uses MFC, but does not use. net. The open file dialog box is not implemented in. net. Instead, it uses a Win32 API function "getopenfilename ".
In this case, I have three options:
- Rewrite your openfiledialog from the beginning.
- Use resources to create your own openfiledialog (Use API "getopenfilename" and create your own template ).
- Crack (hack). Net openfiledialog and add the functions I need on it.
Option (a) is not suitable for me, because it takes a lot of development time and I have a lot of work to complete, and may need to re-check after writing. The subsequent selection requires the creation of templates to use Win32 API calls and resources. Select (c) is a more promising option. Don't think that hack is bad. Basically, hack is when you want to implement some extended functions of the control, but you must start from other threads or processes.
Because I like the challenge, I decided to use the "hack" openfiledialog class to create my custom controls.
What can it do for you?
I could have cracked the control to make it what I wanted, and I did the same thing, but I was in. NET 1.0 has encountered this problem many times, so far no one has provided a solution to this problem. Therefore, I decided to write an interface for this control so that it can be used in different programs.
You also need to create a project that does not need to change or add code to the current project, and can add multiple controls without knowing how it works. It should be a separate control to be added, just like other controls in IDE.
This control is called "openfiledialogex ".
How can I use it?
Imagine if "openfiledialogex" is an abstract class -- I don't set this class as abstract, but because vs ide cannot create an instance of an abstract class, it rejects screen painting.
You can use the openfiledialogex class intact, but this is meaningless, because it does not include the extension function, it is an empty usercontrol.
Therefore, you must inherit openfiledialogex to create the "open file dialog box" for your custom version ".
After inheriting openfiledialogex, you have created a custom control. You can add any controls, such as buttons, panels, and groupboxes ). Basically, it is a control container, and then the container will be "mounted" to the. NET openfiledialog object.
This control has three additional attributes, three methods, and two events different from any usercontrol.
Attribute:
Defaultviewmode:
This attribute allows you to choose the initial viewing mode of openfiledialogex. By default, "details" is used. (Note: in my system, the default value is "list", which should be related to system settings ). You can specify different viewing modes, such as "icon", "list", "thumbnail", and "details.
Startlocation:
This attribute indicates that the control should be attached to the right, bottom, or inside of the standard openfiledialog. Generally, it is used to horizontally expand openfiledialog. In addition, if you need to add additional controls to openfiledialog, you can set them to "NONE". The controls in openfiledialogex will share the same client area with the original openfiledialog ).
Opendialog:
This attribute indicates the embedded openfiledialog in the control. You can set the standard attributes of the open file dialog box, such as initialdirectory, addextension, and filters.
By default, openfiledialog can change the size, as can be seen in the openfiledialogex control and can be automatically scaled. When you expand or contract a window, it varies according to the startlocation attribute.
Startlocation
- Right: The user control is scaled vertically.
- Bottom: horizontal scaling of User Controls
- None: the user control is automatically scaled in two directions.
Basically, when you add controls such as button, panel, and group box, you need to set the anchor attribute for each control, then you can control the position of each control when the size of the openfiledialog window is changed.
For example, to get an image preview, you can set startlocation to right, add a picturebox to the control that inherits openfiledialogex, and set the anchor attribute of picturebox to left, top, right, and bottom. In this way, when the user changes the size, picturebox also scales dynamically.
Method:
These methods are all virtual methods. You need to reload them to interact with the original openfiledialog.
Onfilenamechanged ()
Called when a user clicks a file.
Onfoldernamechanged ()
Called when the user changes the folder.
Onclosing ()
It is called when openfiledialog is ready to be disabled and is useful when releasing allocated resources.
Event:
The two events are filenamechanged and foldernamechanged, which are triggered by the corresponding virtual methods "onfilenamechanged ()" and "onfoldernamechaned. We recommend that you do not directly use events, but rewrite those methods because event data is processed at this layer and is not passed to more layers.
How is it written?
The first problem is that openfiledialog is a modal dialog box, which means you basically cannot obtain the window handle, because when you call the showdialog () method, as long as openfiledialog is open, you have no control over the program process.
To obtain the handle of openfiledialog, You can overload the wndproc method of the form and monitor the message. After openfiledialog is created, the main form receives messages, such as wm_idle, wm_activate, and wm_nc_activate. The parameter lparam is set for these messages, which contains the window handle of openfiledialog.
As you can see, you need to reload the wndproc method. Some developers do not even know the existence of this method. I don't want to repeat the same mistakes, and I will pay attention to some problems that occur when opening openfiledialog in the MDI window.
Next, when the showdialog () method is called, create a "shadow" form on the screen and hide it, this form takes over opening openfiledialog and obtains its window handle.
At first it listened to the wm_idle message, but the problem was that it was too late when the message was sent, the window had been created and displayed on the screen, and you could change its content, however, you will see a slight flicker between the original openfiledialog and custom controls on the screen.
Therefore, we can use the message wm_activate, which occurs before the openfiledialog is displayed on the screen.
At this point, it obtains the required handle and will be displayed. What then?
How does it change the properties of the openfiledialog window?
The nativewindow class of. NET is involved here. This class is used to encapsulate the Window Process of the message sent by the corresponding handle. You can create an nativewindow to connect it to the openfiledialog handle. In this way, every message sent to openfiledialog will be redirected to the wndproc method in nativewindow, which can be blocked, modified, or unblocked.
In wndproc, we process the message wm_windowposchanging. If the dialog box is being opened, change the original horizontal or vertical size based on the user-defined startlocation attribute, that is, increase the size of the window to be created. This occurs only once when the control is opened.
The message wm_showwindow is also processed. Here, all the controls in the original openfiledialog have been created. We need to "Attach" our own controls to the above. This is done by a Win32 API "setparent", which allows you to change the parent window. The following describes how to "APPEND" our control to the position set on the original openfiledialog Based on the startlocation property value.
The advantage of this is that we still have complete control over the controls attached to openfiledialog. This means that we can accept events, call methods, and do anything we need for these controls.
At the same time, we also get the handle of each control on the original openfiledialog, so that we can create a. Net nativewindow object again to process messages of each control.
Ready, how can I monitor messages when users click in listview?
Originally, I tried to create an nativewindow to process the messages sent by the listview itself, but the problem was that the handles were destroyed every time the user changed the directory or clicked in different views, the handle must be rebuilt.
Using MS spy to analyze all the windows of openfiledialog, we noticed that there is another filedialog window in openfiledialog, which is probably the base class window of openfiledialog. Check the msdn document. We can see that each action sent by openfiledialog will trigger a wm_notify message containing the ofnotify structure, which contains the code of that action. Two actions are cdn_selchange and cdn_folderchange.
They are called when users interact with the folder combo box or list box. Next, I first obtain the filewindow handle of the base class object and create an nativewindow object. In this way, wm_notify can be processed to analyze the ofnotify structure and process cdn_selchange and cdn_folderchange. When processing a message in this window, the message is transferred to the onfilenamechanged and onfoldernamechanged methods of the openfiledialogex control.
Another method is to intercept the openfiledialog window when it is closed. At the beginning, I used the message wm_close, which also worked, but later I found that the message was not called when the user double-clicked the file in the list box. View the messages generated by openfiledialog. We can see that the wm_ime_notify message is used. When openfiledialog is disabled, the message will be sent with a wparam parameter with the value of imn_closestatuswindow, in this way, you can pass the call to the onclosingdialog () method ().
How can I scale usercontrol when the size of openfiledialog is changed? This is done by processing the message wm_windowposchanging. Here we set the control to change the size with the size of openfiledialog.
As an important detail, when openfiledialog is disabled, the original size must be restored when we open it. This is because openfiledialog may record the last position and size. If this is not done, each time openfiledialog is opened, it will increase the size, making it bigger and bigger.
Conclusion
I'm running normally on Windows XP, but I have no chance to test on different operating systems such as Windows 2000/2003 or Vista, but it should be okay. I cannot run it on Windows 95/98, because I set the size of struct to be only applicable to winnt systems. If you have any suggestions or any bugs, please let me know and I will update the control.