简体   繁体   English

如何选择文件夹在WFP C#项目中保存文件?

[英]How to choose folder to save a file in WFP C# project?

private void btn_Save_Click(object sender, RoutedEventArgs e)
    {
        string imgPath = @"C:\Temp\image.gif"; //Where file saves to

        string argument = "/select, \"" + imgPath + "\"";

        System.Diagnostics.Process.Start("explorer.exe", argument);

        MemoryStream ms = new MemoryStream();  //Memory stream :)
        FileStream fs = new FileStream(imgPath, FileMode.Create); //  File stream :)

        //rtb - the object of RenderTargetBitmap class
        RenderTargetBitmap rtb = new RenderTargetBitmap((int)InkCanvas1.Width, (int)InkCanvas1.Height, 96, 96, PixelFormats.Default);
        rtb.Render(InkCanvas1);

        GifBitmapEncoder gifEnc = new GifBitmapEncoder(); //saving a file in GIF
        gifEnc.Frames.Add(BitmapFrame.Create(rtb));
        gifEnc.Save(fs);
        fs.Close();
        MessageBox.Show("THE FILE HAS BEEN SAVED, " + imgPath);
    }

This code saves my file to the directory whichis written in imgPath and then explorer opens with no ability to choose a folder and resave this file there, how can I choose a folder??? 此代码将我的文件保存到用imgPath编写的目录中,然后资源管理器打开,无法选择文件夹并将其重新保存到该位置,我该如何选择文件夹?

Try this code: 试试这个代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

static class ShowSelectedInExplorer
{
    [Flags]
    internal enum SHCONT : ushort
    {
        SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
        SHCONTF_FOLDERS = 0x0020,
        SHCONTF_NONFOLDERS = 0x0040,
        SHCONTF_INCLUDEHIDDEN = 0x0080,
        SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
        SHCONTF_NETPRINTERSRCH = 0x0200,
        SHCONTF_SHAREABLE = 0x0400,
        SHCONTF_STORAGE = 0x0800,
        SHCONTF_NAVIGATION_ENUM = 0x1000,
        SHCONTF_FASTITEMS = 0x2000,
        SHCONTF_FLATLIST = 0x4000,
        SHCONTF_ENABLE_ASYNC = 0x8000
    }

    [ComImport,
    Guid("000214E6-0000-0000-C000-000000000046"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
    ComConversionLoss]
    internal interface IShellFolder
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAttributes);
        [PreserveSig]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int EnumObjects([In] IntPtr hwnd, [In] SHCONT grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenumIDList);

        [PreserveSig]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int BindToObject([In] IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void BindToStorage([In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, out IntPtr ppv);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void CompareIDs([In] IntPtr lParam, [In] ref IntPtr pidl1, [In] ref IntPtr pidl2);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void GetAttributesOf([In] uint cidl, [In] IntPtr apidl, [In, Out] ref uint rgfInOut);


        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void GetUIObjectOf([In] IntPtr hwndOwner, [In] uint cidl, [In] IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void GetDisplayNameOf([In] ref IntPtr pidl, [In] uint uFlags, out IntPtr pName);

        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void SetNameOf([In] IntPtr hwnd, [In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, [In] uint uFlags, [Out] IntPtr ppidlOut);
    }

    [ComImport,
    Guid("000214F2-0000-0000-C000-000000000046"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IEnumIDList
    {
        [PreserveSig]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int Next(uint celt, IntPtr rgelt, out uint pceltFetched);

        [PreserveSig]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int Skip([In] uint celt);

        [PreserveSig]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int Reset();

        [PreserveSig]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int Clone([MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum);
    }

    class NativeMethods
    {
        static readonly int pointerSize = Marshal.SizeOf(typeof(IntPtr));

        [DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
        public static extern int CreateBindCtx_(int reserved, out IBindCtx ppbc);

        public static IBindCtx CreateBindCtx()
        {
            IBindCtx result;
            Marshal.ThrowExceptionForHR(CreateBindCtx_(0, out result));
            return result;
        }

        [DllImport("shell32.dll", EntryPoint = "SHGetDesktopFolder", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern int SHGetDesktopFolder_([MarshalAs(UnmanagedType.Interface)] out IShellFolder ppshf);

        public static IShellFolder SHGetDesktopFolder()
        {
            IShellFolder result;
            Marshal.ThrowExceptionForHR(SHGetDesktopFolder_(out result));
            return result;
        }

        [DllImport("shell32.dll", EntryPoint = "SHOpenFolderAndSelectItems")]
        static extern int SHOpenFolderAndSelectItems_(
            [In] IntPtr pidlFolder, uint cidl, [In, Optional, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, int dwFlags
            );

        public static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, int dwFlags)
        {
            var cidl = (apidl != null) ? (uint)apidl.Length : 0U;
            var result = NativeMethods.SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags);
            Marshal.ThrowExceptionForHR(result);
        }

        [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath);

        [DllImport("shell32.dll")]
        public static extern void ILFree([In] IntPtr pidl);
    }

    static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName)
    {
        var bindCtx = NativeMethods.CreateBindCtx();

        uint pchEaten;
        uint pdwAttributes = 0;
        IntPtr ppidl;
        parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAttributes);

        return ppidl;
    }

    static IntPtr PathToAbsolutePIDL(string path)
    {
        var desktopFolder = NativeMethods.SHGetDesktopFolder();
        return GetShellFolderChildrenRelativePIDL(desktopFolder, path);
    }

    static Guid IID_IShellFolder = typeof(IShellFolder).GUID;
    static int pointerSize = Marshal.SizeOf(typeof(IntPtr));

    static IShellFolder PIDLToShellFolder(IShellFolder parent, IntPtr pidl)
    {
        IShellFolder folder;
        var result = parent.BindToObject(pidl, null, ref IID_IShellFolder, out folder);
        Marshal.ThrowExceptionForHR((int)result);
        return folder;
    }

    static IShellFolder PIDLToShellFolder(IntPtr pidl)
    {
        return PIDLToShellFolder(NativeMethods.SHGetDesktopFolder(), pidl);
    }

    static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, bool edit)
    {
        NativeMethods.SHOpenFolderAndSelectItems(pidlFolder, apidl, edit ? 1 : 0);
    }

    public static void FileOrFolder(string path, bool edit = false)
    {
        if (path == null) throw new ArgumentNullException("path");

        var pidl = PathToAbsolutePIDL(path);
        try
        {
            SHOpenFolderAndSelectItems(pidl, null, edit);
        }
        finally
        {
            NativeMethods.ILFree(pidl);
        }
    }

    static IEnumerable<FileSystemInfo> PathToFileSystemInfo(IEnumerable<string> paths)
    {
        foreach (var path in paths)
        {
            string fixedPath = path;
            if (fixedPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || fixedPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
            {
                fixedPath = fixedPath.Remove(fixedPath.Length - 1);
            }

            if (Directory.Exists(fixedPath)) yield return new DirectoryInfo(fixedPath);
            else if (File.Exists(fixedPath)) yield return new FileInfo(fixedPath);
            else
            {
                throw new FileNotFoundException("The specified file or folder doesn't exists : " + fixedPath, fixedPath);
            }
        }
    }

    public static void FilesOrFolders(string parentDirectory, ICollection<string> filenames)
    {
        if (filenames == null) throw new ArgumentNullException("filenames");
        if (filenames.Count == 0) return;

        var parentPidl = PathToAbsolutePIDL(parentDirectory);
        try
        {
            var parent = PIDLToShellFolder(parentPidl);

            List<IntPtr> filesPidl = new List<IntPtr>(filenames.Count);
            foreach (var filename in filenames)
            {
                filesPidl.Add(GetShellFolderChildrenRelativePIDL(parent, filename));
            }

            try
            {
                SHOpenFolderAndSelectItems(parentPidl, filesPidl.ToArray(), false);
            }
            finally
            {
                foreach (var pidl in filesPidl)
                {
                    NativeMethods.ILFree(pidl);
                }
            }
        }
        finally
        {
            NativeMethods.ILFree(parentPidl);
        }
    }

    public static void FilesOrFolders(params string[] paths)
    {
        FilesOrFolders((IEnumerable<string>)paths);
    }

    public static void FilesOrFolders(IEnumerable<string> paths)
    {
        FilesOrFolders(PathToFileSystemInfo(paths));
    }

    public static void FilesOrFolders(IEnumerable<FileSystemInfo> paths)
    {
        if (paths == null) throw new ArgumentNullException("paths");
        if (paths.Count() == 0) return;

        var explorerWindows = paths.GroupBy(p => Path.GetDirectoryName(p.FullName));

        foreach (var explorerWindowPaths in explorerWindows)
        {
            var parentDirectory = Path.GetDirectoryName(explorerWindowPaths.First().FullName);
            FilesOrFolders(parentDirectory, explorerWindowPaths.Select(fsi => fsi.Name).ToList());
        }
    }
}

Usage: 用法:

 ShowSelectedInExplorer.FilesOrFolders(@"C:\Temp\image.gif");

The question is a bit unclear as the code doesn't create or use a file saved in C:\\Temp . 这个问题还不清楚,因为代码不会创建或使用保存在C:\\Temp的文件。 It just uses this hard-coded name. 它仅使用此硬编码名称。 I assume the real question is how to save to a specific file, not how to select a folder. 我认为真正的问题是如何保存到特定文件,而不是如何选择文件夹。

You can do this easily with the SaveFileDialog class : 您可以使用SaveFileDialog类轻松完成此操作:

var dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "image.gif"; 
dlg.DefaultExt = ".gif"; 
dlg.Filter = "GIF files (.gif)|*.gif"; 
// `ShowDialog` returns a bool?
if(dlg.ShowDialog()==true)
{
    using(var fs=dlg.OpenFile())
    {
        var rtb = new RenderTargetBitmap((int)InkCanvas1.Width, (int)InkCanvas1.Height, 96, 96, PixelFormats.Default);
        rtb.Render(InkCanvas1);

        vargifEnc = new GifBitmapEncoder(); //saving a file in GIF
        gifEnc.Frames.Add(BitmapFrame.Create(rtb));
        gifEnc.Save(fs);
    }
    MessageBox.Show($"THE FILE HAS BEEN SAVED, {dlg.FileName}");
}

You can use the FileName propert to retrieve the selected name if you want to override the user's selection : 如果要覆盖用户的选择,可以使用FileName属性检索所选名称:

if(dlg.ShowDialog()==true)
{
    var fileName=Path.ChangeExtension(dlg.FileName,".gif");
    using(var fs=File.Open(fileName))
    {
        ...
    }
    MessageBox.Show($"THE FILE HAS BEEN SAVED, {fileName}");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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