简体   繁体   中英

Microsoft.Win32.OpenFileDialog WPF

I'm using Microsoft.win32.OpenFileDialog to open SQLCE databases files (.sdf). I have added the following filter *.sdf so it only shows the .sdf files, but I also require it to remove a specific .sdf file from the dialogue window. The name of the database I want to remove is fixed, but i have no control over what the other databases are called as they are created via the application and the user decides what they want to name them via the application.

An example of what i want to achieve is, say i have the following databases

Database1.sdf Database2.sdf Database3.sdf

I want to get all except database2.sdf

any help will be appreciated

The OFD is tricky. It is a general-purpose file picker, meant to be "as helpful as possible" - for files. The filters are just little helpers to the users. They DO NOT block picking other files.

Run the Paintbrush or your application, open the file picker. In the filetype combobox probably you will see some filter and indeed the dialog will show that files only. Enter "*" as the file name and press OK/Enter. Almost surely will now see all files regardless to the filter .

Is this behavior OK for your use? If you want to hide some files from that dialog, I think it is not. If I'm right, then the OFD is simply not for you, and you should write your own simple "SDF database picker", build over a ListView/etc that will just list what you want to show.

Elsewise, if this is OK, then you may fetch the HANDLE (in .Net they are passed as an IntPtr ) to the window, then inspect the window structure to find a (IIRC) SysListView control on it, then talk to it to remove the unwanted elements. All the job will be done by C++ or by P/Invoke. I'll try to find some links if you really need it. Drop me a note.

--
For starters, sorry for mistyping the component name. The window clas is SysListView32 .

At first, skim through some of the articles. Be careful because most of then refer to the System.Windows.Forms, not the WPF. Most of the informations is correct and relevant, because internally, it is still the same component, jsut wrapped a bit differently.

Once you have succeeded in intercepting the action of opening the window, and you got the HANDLE (IntPtr) to the SHELLDLL_DefView/SysListView32 control, you are ready to play the real game.

The control, despite its name "SysListView32" is actually named "ListView" and comes from comctl32.dll that is almost as old as the windows itself. You can quite easily dynamically reconfigure the control by sending "raw winapi messages" to it, but the ugly thing is, there is no pretty way to do it in .Net. You'll have to P/Invoke to SendMessage so read about that function on MSDN too. Its first parameter, the HWND is nothing other than the HANDLE (IntPtr) that you just found (HWND = [H]andle-to-[W]i[ND]ow).

The control called "ListView" understands whole lot of different messages. The control is a Window, so it understands WM_xxxx messages ([W]indow[M]essage_xxx). And also understands blahblahblah, and more importantly, it also defines its own API in form of LVM_xxxx messages ([L]ist[V]iew[M]essage_xxxx), for example LVM_GETITEM . Please not that on that LVM_GETITEM page there is a huge list of other LVM_xxx messages: GETITEMCOUNT, INSERTITEM, DELETEITEM etc. The LVM_DELETEITEM is one of the keys to your goal. Here is an example in VB on how to delete "the item in third row". A row, because the ListView's natural view is grid/row based. The desktop-like display mode is an addition, every item is still logically considered to be in consecutive rows, not on XY grid cells. Well, OK, except the DESKTOP and the free form icon placement, which is also done by the SysListView32, but that's another story..

Here is a nice set of articles about ListViews: http://msdn.microsoft.com/en-us/library/windows/desktop/bb774737(v=vs.85).aspx Mind that you will have to translate everything to C# and P/Invoke.

The native control is named ListView, and in fact, the [System.Windows.Forms.ListView] is the .Net wrapper for it! However, there is no pretty way of binding an instance of that class to a pre-existing native component instance. That class is designed to create a new native ListView component from scratch. If you have the skill or luck on googling, you can try to bind such ListView to the native Listview and then you will skip some the P/Invoke hassle, but I do not think it is really worth it..

Driving/patching/hotifxing the controls manually is even bit more complicated, for example, you may sometimes have to kick them to remember them to update the screen after changes: http://www.codeproject.com/Questions/181852/ListView-corrupt-after-LVM_DELETEITEM-message . More to it, filtering the items is not a one-time job. As the user navigates up and down the folder tree you have to filter tham again and again. You have to find a way to get notified when the user displays some new content of another folder. Fortunatelly, everyone who uses LVM is bound to use the same API that now you use. This means that the file dialog must send a series of LVI_DELETExxx/LVI_INSERTxxx messages to the control, and you may trying to intercept+inspect+filterout them, so the "bad items" will get kicked out on the fly as the items are put onto the list.. This is my suggestion on how to do that "easily".

I hope this helps you to solve your problem. In overall, it is not easy unless you have worked with native controls and P/Invoke a few times earlier. I only encourage you to rethink your problem: can it really not be solved in a simple file name validation plus a messagebox "sorry, you cannot use this file"? It would be several orders of magnitude easier..

I'm sorry I couldn't find any whole/exact code for fetching the handles, and reading and deleting the items. I know I've seen such examples few years ago, but now I cannot find any :( Maybe I'll have some time to scratch an example, but do not count on that, I dont know when I'll have the time to play further with that problem.

One problem you will run into is that, even if the file can be hidden in the file browser, the user can still type the filename into the text part of the dialog. The file does exist, so it'll be a valid selection as far as the dialog's concerned, and that behaviour will be difficult to override.

You can't easily force the dialog to not select files that do exist, but you can easily validate the data that the dialog returns. I'd suggest you validate the filename after the dialog closes, and react appropriately.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM