簡體   English   中英

自定義保存文件對話框與底層操作系統保存對話框C#類似

[英]Customize Save file dialog to be similar to underlying OS save dialog C#

我一直在使用這個例子來自定義保存對話框,

http://www.codeproject.com/Articles/19566/Extend-OpenFileDialog-and-SaveFileDialog-the-easy

這很好用,我也可以自定義對話框。 但是,我看到自定義對話框不遵循基礎窗口樣式。 例如,如果我在Windows 7中,對話框將如下所示,

在此輸入圖像描述

這是一個來自word的保存對話框,它確實有很少的選項,如標簽和東西。 但外觀與OS保存對話框相同。 但是,帶有上述鏈接的自定義保存對話框將如下所示,

在此輸入圖像描述

為什么它不遵循操作系統提供的? 有辦法處理這個嗎?


好的,我研究了一下,並且到了可以使用Microsoft.WindowsAPICodePack.Dialogs的CommonSaveFileDialog並創建底層的Save對話框(它與Windows 7樣式匹配)。 我安裝了WindowsAPI shell包並使用CommonSaveFileDialog控件來創建這樣的東西,

在此輸入圖像描述

以紅色標記的控件實際上是CommonFileDialogLabel / CommonFileDialogTextBox / CommonFileDialogComboBox等,它們在這些API中提供。 但現在我的問題是如何添加用戶控件/自定義控件? 我需要完全控制我添加的內容,因此它可以是用戶控件。 任何想法..請幫助謝謝。

建議的解決方案如下所述:

“另存為文件”對話框(在此示例中使用)與用戶控件相關聯,稱為CustomSaveFileDialog。 它的優點是它存在於工具箱中,並且它自動實現IDisposable接口。 但是,它也可能是一個簡單的C#類。

此控件具有一個構造函數,該構造函數接受任意特定於應用程序的用戶控件,該控件托管將在文件對話框中顯示的所有元素。 當我提出正確的問題時,這就是所需要的。

CustomSaveFileDialog具有以下屬性:

  • 接受任意用戶控件停靠在文件對話框的底部,即它們跟隨文件對話框的大小調整
  • 其他元素(按鈕,圖像,復選框等)不需要特殊行為。 它們的行為很正常,就像在其他窗口中一樣。

這是所描述的類的代碼:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace customSaveFileDialog
{
    public partial class CustomSaveFileDialog : UserControl
    {
        //https://stackoverflow.com/questions/9665579/setting-up-hook-on-windows-messages
        delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
            IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);

        const uint WINEVENT_OUTOFCONTEXT = 0;

        [DllImport("user32.dll")]
        private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
           hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
           uint idThread, uint dwFlags);

        [DllImport("user32.dll")]
        private static extern bool UnhookWinEvent(IntPtr hWinEventHook);

        [DllImport("user32.dll")]
        private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
        private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }

        [DllImport("user32.dll")]
        private static extern bool GetClientRect(IntPtr hWnd, out RECT rc);

        [DllImport("kernel32.dll")]
        private static extern uint GetLastError();

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetParent(IntPtr hwndChild, IntPtr hwndNewParent);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr GetParent(IntPtr hWnd);

        private IntPtr hDlg;        // Save As dialog handle
        private IntPtr hHook;       // Event hook
        private IntPtr hCtrl;       // App. specific user control handle

        UserControl ctrl;           // App. specific user control

        //Static variable containing the instance object
        private static CustomSaveFileDialog customSaveFileDialog;

        //public property for the user
        //theSaveFileDialog has been added to the control in the designer from the Toolbox
        public SaveFileDialog Dlg { get { return theSaveFileDialog; } }

        //Event hook delegate
        private static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ctrl">The User Control to be displayed in the file dialog</param>
        public CustomSaveFileDialog(UserControl ctrl)
        {
            InitializeComponent();

            customSaveFileDialog = this;
            this.ctrl = ctrl;
            hCtrl = ctrl.Handle;

            //Setup Hook; for simplicity, hook all possible events from the current process
            hHook = SetWinEventHook(1, 0x7fffffff, IntPtr.Zero,
                    procDelegate, (uint)Process.GetCurrentProcess().Id, 0, WINEVENT_OUTOFCONTEXT);
        }


        // Hook function
        static void WinEventProc(IntPtr hWinEventHook, uint eventType,
            IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
        {
            CustomSaveFileDialog csfdg = customSaveFileDialog;
            if (csfdg.hDlg == IntPtr.Zero)
                csfdg.hDlg = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "#32770", "Save As");

            if (hwnd == csfdg.hDlg) 
            {
                IntPtr hParent = GetParent(csfdg.hCtrl);

                //this is done only once
                if (!(hParent == csfdg.hDlg))
                    SetParent(csfdg.hCtrl, csfdg.hDlg);   //Bind the user control to the Common Dialog

                RECT cliRect;
                GetClientRect(csfdg.hDlg, out cliRect);

                //Position the button in the file dialog
                MoveWindow(csfdg.hCtrl, cliRect.Left + 130, cliRect.Bottom - 55, 500, 60, true);
            }
        }
    }
}

關鍵部分是掛窗事件。 這是從那篇文章中獲得的

可以注意到,“FindWindowEx”函數(在WinEventProc中)找到標題為“另存為”的所有公共對話框(可能還有更多)。 如果這應該是一個問題,則需要更多的過濾,例如通過僅搜索當前線程。 這種搜索功能可以在這里找到。

另外(在上面的代碼中沒有顯示)CustormSaveFileDialog.desinger.cs中的“Dispose”方法包含帶有hHook句柄作為參數的Unhook函數。

該軟件已在Windows7的調試模式下進行了測試。 作為測試,已經實現了一個帶按鈕的簡單窗體窗口:

        //Test for the customized "Save As" dialog
        private void button1_Click(object sender, EventArgs e)
        {
            //Arbitrary User Control
            myUserControl ctrl = new myUserControl();

            using (CustomSaveFileDialog csfdg = new CustomSaveFileDialog(ctrl))
            {
                csfdg.Dlg.FileName = "test";

                //Show the Save As dialog associated to the CustomFileDialog control
                DialogResult res = csfdg.Dlg.ShowDialog();
                if (res == System.Windows.Forms.DialogResult.OK)
                    MessageBox.Show("Save Dialog Finished");
            }
        }

並且 - 以及測試 - 應用程序特定的用戶控件處理以下事件:

using System;
using System.Windows.Forms;

namespace CustomFile
{
    public partial class myUserControl : UserControl
    {
        public myUserControl()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Button Clicked");
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Image Clicked");

        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (!checkBox1.Checked)
                pictureBox1.Visible = false;
            else
                pictureBox1.Visible = true;
        }
    }
}

生成以下輸出:

在此輸入圖像描述

下一張圖片顯示另一個屏幕截圖,文件對話框已調整大小,並且未選中顯示圖像的復選框。

在此輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM