Переглянути джерело

ComPDFKit.Demo(win) - 新增文档压缩Demo

TangJinZhou 4 місяців тому
батько
коміт
892d8f5147

+ 532 - 0
Demo/Examples/Compdfkit.Controls/Common/BaseControl/MessageBoxEx.cs

@@ -0,0 +1,532 @@
+using System;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using ComPDFKit.Controls.Helper;
+
+namespace ComPDFKit.Controls.Common
+{
+    public class MessageBoxEx
+    {
+        private static string[] okstring = new string[] { LanguageHelper.CompressManager.GetString("Main_Ok")};
+        private static string[] ok = okstring;
+
+        private static string[] okcancelstring = new string[] { LanguageHelper.CompressManager.GetString("Main_Ok") , LanguageHelper.CompressManager.GetString("Main_Cancel")};
+        private static string[] okcancel = okcancelstring;
+
+        private static string[] abortretryignorestring = new string[] { LanguageHelper.CompressManager.GetString("Main_MenuHelp_About") , "Retry", "Ignore" };
+        private static string[] abortretryignore = abortretryignorestring;
+
+        private static string[] yesnocancelstring = new string[] { LanguageHelper.CompressManager.GetString("Main_Yes"), LanguageHelper.CompressManager.GetString("Main_No"), LanguageHelper.CompressManager.GetString("Main_Cancel") };
+        private static string[] yesnocancel = yesnocancelstring;
+
+        private static string[] yesnostring = new string[] { LanguageHelper.CompressManager.GetString("Main_Yes"), LanguageHelper.CompressManager.GetString("Main_No") };
+        private static string[] yesno = yesnostring;
+
+        private static string[] retrycancelstring = new string[] { "Retry", LanguageHelper.CompressManager.GetString("Main_Cancel") };
+        private static string[] retrycancel = retrycancelstring;
+
+        public static DialogResult Show(string text,string[] buttonTitles = null)
+        {
+            if(buttonTitles!=null&&buttonTitles.Length==1)
+            {
+                ok = buttonTitles;
+            }
+            else
+            {
+                ok = okstring;
+            }
+
+            myProc = new HookProc(OK);
+            SetHook();
+            DialogResult result = MessageBox.Show(text, Application.ProductName,MessageBoxButtons.OK);
+            
+            UnHook();
+
+            return result;
+        }
+
+        public static DialogResult Show(string text,string title,string[] buttonTitles = null)
+        {
+            if (buttonTitles != null && buttonTitles.Length == 1)
+            {
+                ok = buttonTitles;
+            }
+            else
+            {
+                ok = okstring;
+            }
+
+            myProc = new HookProc(OK);
+            SetHook();
+            DialogResult result = MessageBox.Show(text,title);
+            UnHook();
+
+            return result;
+        }
+
+        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, string[] buttonTitles=null)
+        {
+            switch (buttons)
+            {
+                case MessageBoxButtons.OK:
+                    if (buttonTitles != null && buttonTitles.Length == 1)
+                    {
+                        ok = buttonTitles;
+                    }
+                    else
+                    {
+                        ok = okstring;
+                    }
+                    myProc = new HookProc(OK);
+                    break;
+                case MessageBoxButtons.OKCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        okcancel = buttonTitles;
+                    }
+                    else
+                    {
+                        okcancel = okcancelstring;
+                    }
+                    myProc = new HookProc(OKCancel);
+                break;
+                case MessageBoxButtons.AbortRetryIgnore:
+                    if (buttonTitles != null && buttonTitles.Length == 3)
+                    {
+                        abortretryignore = buttonTitles;
+                    }
+                    else
+                    {
+                        abortretryignore = abortretryignorestring;
+                    }
+                    myProc = new HookProc(AbortRetryIgnore);
+                    break;
+                case MessageBoxButtons.YesNoCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 3)
+                    {
+                        yesnocancel = buttonTitles;
+                    }
+                    else
+                    {
+                        yesnocancel = yesnocancelstring;
+                    }
+                    myProc = new HookProc(YesNoCancel);
+                    break;
+                case MessageBoxButtons.YesNo:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        yesno = buttonTitles;
+                    }
+                    else
+                    {
+                        yesno = yesnostring;
+                    }
+                    myProc = new HookProc(YesNo);
+                    break;
+                case MessageBoxButtons.RetryCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        retrycancel = buttonTitles;
+                    }
+                    else
+                    {
+                        retrycancel = retrycancelstring;
+                    }
+                    myProc = new HookProc(RetryCancel);
+                    break;
+                default:
+                    break;
+            }
+
+            SetHook();
+            DialogResult result = MessageBox.Show(text, string.IsNullOrEmpty(caption)?Application.ProductName:caption, buttons);
+            UnHook();
+            return result;
+        }
+
+        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons,MessageBoxIcon icons,string[] buttonTitles = null)
+        {
+            switch (buttons)
+            {
+                case MessageBoxButtons.OK:
+                    if (buttonTitles != null && buttonTitles.Length == 1)
+                    {
+                        ok = buttonTitles;
+                    }
+                    else
+                    {
+                        ok = okstring;
+                    }
+                    myProc = new HookProc(OK);
+                    break;
+                case MessageBoxButtons.OKCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        okcancel = buttonTitles;
+                    }
+                    else
+                    {
+                        okcancel = okcancelstring;
+                    }
+                    myProc = new HookProc(OKCancel);
+                    break;
+                case MessageBoxButtons.AbortRetryIgnore:
+                    if (buttonTitles != null && buttonTitles.Length == 3)
+                    {
+                        abortretryignore = buttonTitles;
+                    }
+                    else
+                    {
+                        abortretryignore = abortretryignorestring;
+                    }
+                    myProc = new HookProc(AbortRetryIgnore);
+                    break;
+                case MessageBoxButtons.YesNoCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 3)
+                    {
+                        yesnocancel = buttonTitles;
+                    }
+                    else
+                    {
+                        yesnocancel = yesnocancelstring;
+                    }
+                    myProc = new HookProc(YesNoCancel);
+                    break;
+                case MessageBoxButtons.YesNo:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        yesno = buttonTitles;
+                    }
+                    else
+                    {
+                        yesno = yesnostring;
+                    }
+                    myProc = new HookProc(YesNo);
+                    break;
+                case MessageBoxButtons.RetryCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        retrycancel = buttonTitles;
+                    }
+                    else
+                    {
+                        retrycancel = retrycancelstring;
+                    }
+                    myProc = new HookProc(RetryCancel);
+                    break;
+                default:
+                    break;
+            }
+            SetHook();
+            DialogResult result = MessageBox.Show(text, string.IsNullOrEmpty(caption) ? Application.ProductName : caption, buttons, icons);
+            UnHook();
+            return result;
+        }
+        
+        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons,
+            MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, string[] buttonTitles=null)
+        {
+            switch (buttons)
+            {
+                case MessageBoxButtons.OK:
+                    if (buttonTitles != null && buttonTitles.Length == 1)
+                    {
+                        ok = buttonTitles;
+                    }
+                    else
+                    {
+                        ok = okstring;
+                    }
+                    myProc = new HookProc(OK);
+                    break;
+                case MessageBoxButtons.OKCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        okcancel = buttonTitles;
+                    }
+                    else
+                    {
+                        okcancel = okcancelstring;
+                    }
+                    myProc = new HookProc(OKCancel);
+                    break;
+                case MessageBoxButtons.AbortRetryIgnore:
+                    if (buttonTitles != null && buttonTitles.Length == 3)
+                    {
+                        abortretryignore = buttonTitles;
+                    }
+                    else
+                    {
+                        abortretryignore = abortretryignorestring;
+                    }
+                    myProc = new HookProc(AbortRetryIgnore);
+                    break;
+                case MessageBoxButtons.YesNoCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 3)
+                    {
+                        yesnocancel = buttonTitles;
+                    }
+                    else
+                    {
+                        yesnocancel = yesnocancelstring;
+                    }
+                    myProc = new HookProc(YesNoCancel);
+                    break;
+                case MessageBoxButtons.YesNo:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        yesno = buttonTitles;
+                    }
+                    else
+                    {
+                        yesno = yesnostring;
+                    }
+                    myProc = new HookProc(YesNo);
+                    break;
+                case MessageBoxButtons.RetryCancel:
+                    if (buttonTitles != null && buttonTitles.Length == 2)
+                    {
+                        retrycancel = buttonTitles;
+                    }
+                    else
+                    {
+                        retrycancel = retrycancelstring;
+                    }
+                    myProc = new HookProc(RetryCancel);
+                    break;
+                default:
+                    break;
+            }
+
+            DialogResult result = MessageBox.Show(text, string.IsNullOrEmpty(caption) ? Application.ProductName : caption, buttons, icon, defaultButton);
+
+            return result;
+        }
+
+        public enum HookType
+        {
+            Keyboard = 2,
+            CBT = 5,
+            Mouse = 7, 
+        };
+
+        [DllImport("kernel32.dll")]
+        static extern int GetCurrentThreadId();
+        [DllImport("user32.dll")]
+        static extern int GetDlgItem(IntPtr hDlg, int nIDDlgItem);
+        [DllImport("user32", EntryPoint = "SetDlgItemText")]
+        static extern int SetDlgItemTextA(IntPtr hDlg, int nIDDlgItem, string lpString);
+
+        [DllImport("user32.dll", EntryPoint = "SetWindowTextW", CharSet = CharSet.Unicode)]
+        private static extern bool SetWindowText(IntPtr hWnd, string lpString);
+        [DllImport("user32.dll")]
+        static extern void UnhookWindowsHookEx(IntPtr handle);
+        [DllImport("user32.dll")]
+        static extern IntPtr SetWindowsHookEx(int idHook, [MarshalAs(UnmanagedType.FunctionPtr)] HookProc lpfn, IntPtr hInstance, int threadID);
+        [DllImport("user32.dll")]
+        static extern IntPtr CallNextHookEx(IntPtr handle, int code, IntPtr wparam, IntPtr lparam);
+
+
+        static IntPtr _nextHookPtr;
+        ////must be global, or it will be Collected by GC, then no callback func can be used for the Hook
+        static HookProc myProc = new HookProc(MyHookProc);
+
+        private delegate IntPtr HookProc(int code, IntPtr wparam, IntPtr lparam);
+
+        private static IntPtr OK(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                hChildWnd = wparam;
+
+                var index = (IntPtr)GetDlgItem(hChildWnd,1);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, ok[0]);
+                }
+            }
+            else
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);
+
+            return IntPtr.Zero;
+        }
+
+        private static IntPtr OKCancel(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;
+            bool result = false;
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                hChildWnd = wparam;
+
+                IntPtr index = (IntPtr)GetDlgItem(hChildWnd, 1);
+                if (index != IntPtr.Zero)
+                {
+                   result = SetWindowText(index, okcancel[0]);
+                }
+                index = (IntPtr)GetDlgItem(hChildWnd, 2);
+                if (index != IntPtr.Zero)
+                {
+                    result = SetWindowText(index, okcancel[1]);
+                }
+            }
+            else
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);
+
+            return IntPtr.Zero;
+        }
+
+        private static IntPtr RetryCancel(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                hChildWnd = wparam;
+
+                var index = (IntPtr)GetDlgItem(hChildWnd,4);
+                if (index!=IntPtr.Zero)
+                {
+                    SetWindowText(index, retrycancel[0]);
+                }
+                index = (IntPtr)GetDlgItem(hChildWnd, 2);
+                if (GetDlgItem(hChildWnd, 2) != 0)
+                {
+                    SetWindowText(index, retrycancel[1]);
+                }
+            }
+            else
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);
+            return IntPtr.Zero;
+        }
+
+        private static IntPtr YesNo(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                hChildWnd = wparam;
+
+                var index = (IntPtr)GetDlgItem(hChildWnd, 6);
+                if (index!=IntPtr.Zero)
+                {
+                    SetWindowText(index, yesno[0]);
+                }
+                index = (IntPtr)GetDlgItem(hChildWnd, 7);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, yesno[1]);
+                }
+            }
+            else
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);
+            return IntPtr.Zero;
+        }
+        private static IntPtr YesNoCancel(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                hChildWnd = wparam;
+
+                var index = (IntPtr)GetDlgItem(hChildWnd, 6);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index,yesnocancel[0]);
+                }
+
+                index = (IntPtr)GetDlgItem(hChildWnd, 7);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, yesnocancel[1]);
+                }
+
+                index = (IntPtr)GetDlgItem(hChildWnd, 2);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, yesnocancel[2]);
+                }
+            }
+            else
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);
+            return IntPtr.Zero;
+        }
+
+        private static IntPtr AbortRetryIgnore(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                hChildWnd = wparam;
+
+                var index = (IntPtr)GetDlgItem(hChildWnd, 3);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, abortretryignore[0]);
+                }
+
+                index = (IntPtr)GetDlgItem(hChildWnd, 4);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, abortretryignore[1]);
+                }
+
+                index = (IntPtr)GetDlgItem(hChildWnd, 5);
+                if (index != IntPtr.Zero)
+                {
+                    SetWindowText(index, abortretryignore[2]);
+                }
+            }
+            else
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);
+            return IntPtr.Zero;
+        }
+
+        private static IntPtr MyHookProc(int code, IntPtr wparam, IntPtr lparam)
+        {
+            IntPtr hChildWnd;// msgbox is "child"
+            // notification that a window is about to be activated
+            // window handle is wParam
+            if (code == 5)//HCBT_ACTIVATE = 5
+            {
+                // set window handles of messagebox
+                hChildWnd = wparam;
+                //to get the text of yes button
+
+                for(int i=0;i<21;i++)
+                {
+                    if (GetDlgItem(hChildWnd, i) != 0)
+                        SetDlgItemTextA(hChildWnd,i,string.Format("Item {0}",i));
+                }
+            }
+            else
+            {
+                CallNextHookEx(_nextHookPtr, code, wparam, lparam);// otherwise, continue with any possible chained hooks
+            }
+
+            return IntPtr.Zero;
+        }
+
+        public static void SetHook()
+        {
+            try
+            {
+                if (_nextHookPtr != IntPtr.Zero)//Hooked already
+                {
+                    return;
+                }
+                _nextHookPtr = SetWindowsHookEx((int)HookType.CBT, myProc, IntPtr.Zero, GetCurrentThreadId());
+            }
+            catch { }
+        }
+
+        public static  void UnHook()
+        {
+            if (_nextHookPtr != IntPtr.Zero)
+            {
+                UnhookWindowsHookEx(_nextHookPtr);
+                _nextHookPtr = IntPtr.Zero;
+            }
+        }
+    }
+}

+ 67 - 2
Demo/Examples/Compdfkit.Controls/Common/Helper/CommonHelper.cs

@@ -59,6 +59,15 @@ namespace ComPDFKit.Controls.Helper
 
     public static class CommonHelper
     {
+        [DllImport("shell32.dll", ExactSpelling = true)]
+        private static extern void ILFree(IntPtr pidlList);
+
+        [DllImport("shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
+        private static extern IntPtr ILCreateFromPathW(string pszPath);
+
+        [DllImport("shell32.dll", ExactSpelling = true)]
+        private static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);
+
         public static bool IsImageCorrupted(string imagePath)
         {
             try
@@ -116,8 +125,6 @@ namespace ComPDFKit.Controls.Helper
             }
         }
 
-
-
         public static int GetBitmapPointer(Bitmap bitmap)
         {
             IntPtr hBitmap = bitmap.GetHbitmap();
@@ -366,6 +373,64 @@ namespace ComPDFKit.Controls.Helper
             }
         }
 
+        public static string CreateFilePath(string path)
+        {
+            int i = 1;
+            string oldDestName = path;
+            do
+            {
+                if (File.Exists(path))
+                {
+                    int lastDot = oldDestName.LastIndexOf('.');
+
+                    string fileExtension = string.Empty;
+
+                    string fileName = oldDestName;
+
+                    if (lastDot > 0)
+                    {
+                        fileExtension = fileName.Substring(lastDot);
+
+                        fileName = fileName.Substring(0, lastDot);
+                    }
+
+                    path = fileName + string.Format(@"({0})", i) + fileExtension;
+                }
+
+                ++i;
+            } while (File.Exists(path));
+
+            return path;
+        }
+
+        public static void ExplorerFile(string filePath)
+        {
+            try
+            {
+                if (!File.Exists(filePath) && !Directory.Exists(filePath))
+                    return;
+
+                if (Directory.Exists(filePath))
+                    Process.Start(@"explorer.exe", "/select,\"" + filePath + "\"");
+                else
+                {
+                    IntPtr pidlList = ILCreateFromPathW(filePath);
+                    if (pidlList != IntPtr.Zero)
+                    {
+                        try
+                        {
+                            Marshal.ThrowExceptionForHR(SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
+                        }
+                        finally
+                        {
+                            ILFree(pidlList);
+                        }
+                    }
+                }
+            }
+            catch { }
+        }
+
         internal static class PageEditHelper
         {
             public static T FindVisualParent<T>(DependencyObject obj) where T : class

+ 1 - 0
Demo/Examples/Compdfkit.Controls/Common/Helper/LanguageHelper.cs

@@ -13,5 +13,6 @@ namespace ComPDFKit.Controls.Helper
         public static ResourceManager DocInfoManager= new ResourceManager("ComPDFKit.Controls.Strings.DocInfo", Assembly.GetExecutingAssembly());
         public static ResourceManager SecurityManager= new ResourceManager("ComPDFKit.Controls.Strings.Security", Assembly.GetExecutingAssembly());
         public static ResourceManager DocEditorManager= new ResourceManager("ComPDFKit.Controls.Strings.DocEditor", Assembly.GetExecutingAssembly());
+        public static ResourceManager CompressManager = new ResourceManager("ComPDFKit.Controls.Strings.Compress", Assembly.GetExecutingAssembly());
     }
 }

+ 8 - 2
Demo/Examples/Compdfkit.Controls/Common/HomePage/HomePageControl.xaml.cs

@@ -13,6 +13,7 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
+using ComPDFKit.Controls.Compress;
 using ComPDFKit.Controls.Helper;
 using Path = System.Windows.Shapes.Path;
 
@@ -159,7 +160,11 @@ namespace ComPDFKit.Controls.PDFControl
                     }
                 case "Compress":
                     {
-                        System.Diagnostics.Process.Start("https://www.compdf.com/contact-sales");
+                        CompressDialog compressDialog = new CompressDialog()
+                        {
+                            Owner = parentWindow
+                        };
+                        compressDialog.ShowDialog();
                         break;
                     }
                 case "Measurement":
@@ -167,6 +172,7 @@ namespace ComPDFKit.Controls.PDFControl
                         OpenFileEvent?.Invoke(this, new OpenFileEventArgs(FileOperationType.OpenFileDirectly, MeasurementFileName, e.Feature));
                         break;
                     }
+
                 default: 
                     break;
             }
@@ -192,6 +198,7 @@ namespace ComPDFKit.Controls.PDFControl
         {
             customItems = new List<CustomItem>()
             {
+                new CustomItem{ IconCanvas = compressCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Compress"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Compress"), Feature = "Compress"},
                 new CustomItem{ IconCanvas = viewerCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Viewer"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Viewer"), Feature = "Viewer"},
                 new CustomItem{ IconCanvas = annotationsCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Annotations"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Annotations"), Feature = "Annotations"},
                 new CustomItem{ IconCanvas = formsCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Forms"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Forms"), Feature = "Forms"},
@@ -203,7 +210,6 @@ namespace ComPDFKit.Controls.PDFControl
                 new CustomItem{ IconCanvas = redactionCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Redaction"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Redaction"), Feature = "Redaction"},
                 new CustomItem{ IconCanvas = compareDocumentsCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_DocCompare"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_DocCompare"), Feature = "Compare Documents"},
                 new CustomItem{ IconCanvas = conversionCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Conversion"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Conversion"), Feature = "Conversion"},
-                new CustomItem{ IconCanvas = compressCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Compress"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Compress"), Feature = "Compress"},
                 new CustomItem{ IconCanvas = measurementCanvas,TitleText = LanguageHelper.CommonManager.GetString("Func_Measurement"), DescriptionText= LanguageHelper.CommonManager.GetString("FuncDetail_Measurement"), Feature = "Measurement"},
             };
         }

+ 4 - 0
Demo/Examples/Compdfkit.Controls/Common/PasswordControl/PasswordWindow.xaml.cs

@@ -23,6 +23,8 @@ namespace ComPDFKit.Controls.Common
         public delegate void DialogCloseEventHandler(object sender, PasswordEventArgs e);
         public event DialogCloseEventHandler DialogClosed;
 
+        public string Password { get; private set; }
+
         public PasswordWindow()
         {
             InitializeComponent();
@@ -67,6 +69,7 @@ namespace ComPDFKit.Controls.Common
                     if (pdfDoc.IsLocked == false)
                     {
                         PasswordEventArgs passwordEventArgs = new PasswordEventArgs(e);
+                        Password = e;
                         CloseWindow(passwordEventArgs);
                     }
                     else
@@ -81,6 +84,7 @@ namespace ComPDFKit.Controls.Common
                         if(pdfDoc.CheckOwnerPassword(e))
                         {
                             PasswordEventArgs passwordEventArgs = new PasswordEventArgs(e);
+                            Password = e;
                             CloseWindow(passwordEventArgs);
                         }
                         else

+ 26 - 0
Demo/Examples/Compdfkit.Controls/Compdfkit.Controls.csproj

@@ -87,6 +87,12 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\WindowsAPICodePack-Core.1.1.1\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
+    </Reference>
     <Reference Include="Nager.Country, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <HintPath>..\packages\Nager.Country.4.0.0\lib\netstandard2.0\Nager.Country.dll</HintPath>
     </Reference>
@@ -173,6 +179,7 @@
     <Compile Include="Common\BaseControl\MatrixRadioControl.xaml.cs">
       <DependentUpon>MatrixRadioControl.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Common\BaseControl\MessageBoxEx.cs" />
     <Compile Include="Common\BaseControl\PageNumberControl.xaml.cs">
       <DependentUpon>PageNumberControl.xaml</DependentUpon>
     </Compile>
@@ -310,6 +317,9 @@
     <Compile Include="Common\PropertyControl\WritableComboBoxControl.xaml.cs">
       <DependentUpon>WritableComboBoxControl.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Compress\CompressDialog.xaml.cs">
+      <DependentUpon>CompressDialog.xaml</DependentUpon>
+    </Compile>
     <Compile Include="DigitalSignature\AddCertificationControl\AddCertificationControl.xaml.cs">
       <DependentUpon>AddCertificationControl.xaml</DependentUpon>
     </Compile>
@@ -573,6 +583,11 @@
     <Compile Include="PDFView\PDFScaling\PDFScalingUI\CPDFScalingUI.xaml.cs">
       <DependentUpon>CPDFScalingUI.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Strings\Compress.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Compress.resx</DependentUpon>
+    </Compile>
     <Compile Include="Watermark\AddWatermark\FileGridListWithPageRangeControl.xaml.cs">
       <DependentUpon>FileGridListWithPageRangeControl.xaml</DependentUpon>
     </Compile>
@@ -657,6 +672,13 @@
     <EmbeddedResource Include="Strings\Common.zh.resx">
       <DependentUpon>Common.resx</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="Strings\Compress.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Compress.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Strings\Compress.zh.resx">
+      <DependentUpon>Compress.resx</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="Strings\DocEditor.resx">
       <Generator>ResXFileCodeGenerator</Generator>
       <LastGenOutput>DocEditor.Designer.cs</LastGenOutput>
@@ -1022,6 +1044,10 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Compress\CompressDialog.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="DigitalSignature\AddCertificationControl\AddCertificationControl.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>

+ 447 - 0
Demo/Examples/Compdfkit.Controls/Compress/CompressDialog.xaml

@@ -0,0 +1,447 @@
+<Window x:Class="ComPDFKit.Controls.Compress.CompressDialog"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:ComPDFKit.Controls.Compress"
+        mc:Ignorable="d"
+        Title="CompressWPFDialog" Height="450" Width="890" ResizeMode="NoResize"
+        ShowInTaskbar="False"
+        WindowStartupLocation="CenterOwner"
+        WindowStyle="SingleBorderWindow">
+	<Window.Resources>
+		<ResourceDictionary>
+			<local:MaxWidthToTextTrimmingConverter x:Key="MaxWidthToTextTrimmingConverter" />
+			<Style x:Key="LeftAlignedHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
+				<Setter Property="HorizontalContentAlignment" Value="Left" />
+			</Style>
+            
+            <Style x:Key="DisabledButtonStyle" TargetType="{x:Type Button}">
+                <Setter Property="BorderThickness" Value="1" />
+                <Setter Property="Padding" Value="5" />
+                <Setter Property="Width" Value="100" />
+                <Setter Property="Height" Value="40" />
+                <Style.Triggers>
+                    <Trigger Property="IsEnabled" Value="False">
+                        <Setter Property="Foreground" Value="Gray" />
+                    </Trigger>
+                </Style.Triggers>
+            </Style>
+            
+			<Style x:Key="ResizableGridViewColumnHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
+				<Setter Property="Template">
+					<Setter.Value>
+						<ControlTemplate TargetType="GridViewColumnHeader">
+							<Grid x:Name="Root" Background="Transparent">
+								<Grid.ColumnDefinitions>
+									<ColumnDefinition Width="*" />
+									<ColumnDefinition Width="Auto" />
+								</Grid.ColumnDefinitions>
+								<ContentPresenter Grid.Column="0" VerticalAlignment="Center" />
+								<Thumb
+                                 x:Name="PART_HeaderGripper"
+                                 Grid.Column="1"
+                                 Width="5"
+                                 HorizontalAlignment="Right"
+                                 Cursor="SizeWE"
+                                 DragDelta="PART_HeaderGripper_DragDelta" />
+							</Grid>
+						</ControlTemplate>
+					</Setter.Value>
+				</Setter>
+			</Style>
+            
+			<Style x:Key="RoundButtonStyle" TargetType="{x:Type Button}">
+				<Setter Property="Background" Value="White" />
+				<Setter Property="BorderBrush" Value="Black" />
+				<Setter Property="BorderThickness" Value="1" />
+				<Setter Property="Padding" Value="5" />
+				<Setter Property="Margin" Value="12,8" />
+				<Setter Property="Width" Value="100" />
+				<Setter Property="Height" Value="40" />
+				<Setter Property="Template">
+					<Setter.Value>
+						<ControlTemplate TargetType="{x:Type Button}">
+							<Border
+                             x:Name="border"
+                             Background="{TemplateBinding Background}"
+                             BorderBrush="{TemplateBinding BorderBrush}"
+                             BorderThickness="{TemplateBinding BorderThickness}"
+                             CornerRadius="0">
+								<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
+							</Border>
+							<ControlTemplate.Triggers>
+								<Trigger Property="IsPressed" Value="True">
+									<Setter TargetName="border" Property="Background" Value="White" />
+									<Setter TargetName="border" Property="BorderBrush" Value="LightGray" />
+								</Trigger>
+								<Trigger Property="IsEnabled" Value="False">
+									<Setter TargetName="border" Property="Opacity" Value="0.5" />
+								</Trigger>
+							</ControlTemplate.Triggers>
+						</ControlTemplate>
+					</Setter.Value>
+				</Setter>
+			</Style>
+
+			<Style x:Key="HeadStyle" TargetType="{x:Type GridViewColumnHeader}">
+				<Setter Property="OverridesDefaultStyle" Value="False" />
+				<Setter Property="HorizontalContentAlignment" Value="Left" />
+
+				<Setter Property="FontSize" Value="14" />
+				<Setter Property="Template">
+					<Setter.Value>
+						<ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
+							<Grid Name="g" Background="Transparent">
+								<Border Name="bd" Padding="{TemplateBinding Padding}">
+									<Grid>
+										<!--  Gripper 控件  -->
+										<Thumb
+                                         x:Name="PART_HeaderGripper"
+                                         Width="5"
+                                         HorizontalAlignment="Right"
+                                         Background="White"
+                                         BorderBrush="LightGray"
+                                         Cursor="SizeWE"
+                                         Visibility="Collapsed" />
+										<ContentPresenter Margin="5,3,0,3" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
+									</Grid>
+								</Border>
+							</Grid>
+							<ControlTemplate.Triggers>
+								<Trigger Property="IsMouseOver" Value="True">
+									<Setter TargetName="g" Property="Background" Value="LightGray" />
+									<Setter TargetName="g" Property="Opacity" Value="0.7" />
+									<Setter TargetName="PART_HeaderGripper" Property="Visibility" Value="Visible" />
+									<Setter TargetName="PART_HeaderGripper" Property="Background" Value="LightGray" />
+									<Setter TargetName="PART_HeaderGripper" Property="Opacity" Value="0.5" />
+								</Trigger>
+							</ControlTemplate.Triggers>
+						</ControlTemplate>
+					</Setter.Value>
+				</Setter>
+			</Style>
+            
+            <Style x:Key="ListViewItemStyle" TargetType="{x:Type ListViewItem}">
+                <Style.Setters>
+                    <Setter Property="HorizontalAlignment" Value="Stretch" />
+                    <Setter Property="SnapsToDevicePixels" Value="True" />
+                    <Setter Property="Foreground" Value="Black" />
+                    <Setter Property="Template">
+                        <Setter.Value>
+                            <ControlTemplate TargetType="{x:Type ListViewItem}">
+                                <Border
+                        x:Name="bd"
+                        Padding="{TemplateBinding Padding}"
+                        BorderBrush="LightGray"
+                                    Background="Transparent"
+                        BorderThickness="1"
+                        SnapsToDevicePixels="True">
+                                    <GridViewRowPresenter
+                            Margin="0,2"
+                            Columns="{TemplateBinding GridView.ColumnCollection}"
+                            Content="{TemplateBinding Content}" />
+                                </Border>
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsSelected" Value="True">
+                                        <Trigger.Setters>
+                                            <Setter TargetName="bd" Property="Background" Value="LightGray" />
+                                            <Setter TargetName="bd" Property="Opacity" Value="0.8" />
+                                        </Trigger.Setters>
+                                    </Trigger>
+                                    <Trigger Property="IsMouseOver" Value="True">
+                                        <Trigger.Setters>
+                                            <Setter TargetName="bd" Property="Background" Value="LightGray" />
+                                            <Setter TargetName="bd" Property="Opacity" Value="0.7" />
+                                            <Setter TargetName="bd" Property="BorderBrush" Value="LightGray" />
+                                        </Trigger.Setters>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </Setter.Value>
+                    </Setter>
+                </Style.Setters>
+            </Style>
+
+            <Style x:Key="BigCustomRadioButtonStyle" TargetType="{x:Type RadioButton}">
+                <Setter Property="Template">
+                    <Setter.Value>
+                        <ControlTemplate TargetType="{x:Type RadioButton}">
+                            <Grid>
+                                <Border x:Name="border">
+                                    <Grid Background="Transparent">
+                                        <Grid.ColumnDefinitions>
+                                            <ColumnDefinition Width="Auto"/>
+                                            <ColumnDefinition Width="*"/>
+                                        </Grid.ColumnDefinitions>
+                                        <Border x:Name="radioButtonBorder" Grid.Column="0" BorderBrush="Black" Width="18" Height="18" Margin="0"  BorderThickness="1.4" CornerRadius="20" SnapsToDevicePixels="True">
+                                            <Path x:Name="checkMark" Fill="Black" StrokeThickness="2" Visibility="Collapsed" Data="M0 5C0 2.23858 2.23858 0 5 0C7.76142 0 10 2.23858 10 5C10 7.76142 7.76142 10 5 10C2.23858 10 0 7.76142 0 5Z" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                                        </Border>
+                                        <ContentPresenter Grid.Column="1" Margin="5,0,0,0" VerticalAlignment="Center" RecognizesAccessKey="True"/>
+                                    </Grid>
+                                </Border>
+                            </Grid>
+                            <ControlTemplate.Triggers>
+                                <Trigger Property="IsChecked" Value="True">
+                                    <Setter TargetName="checkMark" Property="Visibility" Value="Visible"/>
+                                </Trigger>
+                                <Trigger Property="IsMouseOver" Value="True">
+                                    <Setter TargetName="radioButtonBorder" Property="Background" Value="#E1E1E1"/>
+                                </Trigger>
+                                <Trigger Property="IsPressed" Value="True">
+                                    <Setter TargetName="radioButtonBorder" Property="Background" Value="#E1E1E1"/>
+                                </Trigger>
+                                <Trigger Property="IsEnabled" Value="False">
+                                    <Setter TargetName="radioButtonBorder" Property="Opacity" Value="0.3"/>
+                                </Trigger>
+                            </ControlTemplate.Triggers>
+                        </ControlTemplate>
+                    </Setter.Value>
+                </Setter>
+            </Style>
+        </ResourceDictionary>
+	</Window.Resources>
+    <Grid>
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="50" />
+                <RowDefinition Height="*" />
+                <RowDefinition Height="50" />
+            </Grid.RowDefinitions>
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="640" />
+                <ColumnDefinition Width="*" />
+            </Grid.ColumnDefinitions>
+            <DockPanel LastChildFill="True">
+                <Button
+                    Margin="12,0,0,0"
+        Name="btnAddFile"
+        MinWidth="112"
+Padding="8,0,8,0"
+        Height="32"
+        Click="btnAddFile_Click"
+        Content=" Add File"
+        DockPanel.Dock="Left"
+        BorderBrush="#33000000" Background="#E1E1E1" BorderThickness="1"  Style="{StaticResource DisabledButtonStyle}" />
+                <StackPanel Name="flowLayoutPanel2" DockPanel.Dock="Right">
+                    <Label
+            Name="lbTotalFiles"
+            Width="120"
+            Height="32"
+            Margin="0,5"
+            HorizontalAlignment="Right"
+            VerticalContentAlignment="Center"
+            Content="Total 10 Files" />
+                </StackPanel>
+            </DockPanel>
+            <StackPanel Name="panel1" Grid.Row="1" >
+
+                <ListView
+             VerticalContentAlignment="Top"
+                    HorizontalAlignment="Left"
+                    Margin="12,0,0,0"
+        Name="CompressListView"
+        Width="620"
+        Height="250"
+        AllowDrop="True"
+        DragOver="ConverterListView_DragOver"
+        Drop="ConverterListView_Drop"
+        ItemContainerStyle="{StaticResource ListViewItemStyle}"
+                    Loaded="ConverterListView_Loaded"
+                    PreviewMouseLeftButtonDown="ConverterListView_PreviewMouseLeftButtonDown"
+                    SizeChanged="ConverterListView_SizeChanged"
+        MouseMove="ConverterListView_MouseMove"
+        PreviewMouseUp="ConverterListView_PreviewMouseUp"
+        SelectionChanged="ConverterListView_SelectionChanged">
+
+                    <ListView.View>
+                        <GridView AllowsColumnReorder="False" ColumnHeaderContainerStyle="{StaticResource HeadStyle}">
+                            <GridViewColumn
+                    x:Name="FileName"
+                    Width="180"
+                    Header="Name">
+                                <GridViewColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
+                                            <Image
+                                    Width="20"
+                                    Height="20"
+                                    Margin="5"
+                                    Source="../../Resources/Image/PDFicon.png"/>
+                                            <TextBlock
+                                    x:Name="TxbName"
+                                    HorizontalAlignment="Center"
+                                    VerticalAlignment="Center"
+                                    SizeChanged="TxbName_SizeChanged"
+                                    Text="{Binding Name}"
+                                    TextAlignment="Left" TextTrimming="CharacterEllipsis">
+                                                <TextBlock.ToolTip>
+                                                    <ToolTip>
+                                                        <TextBlock Text="{Binding Name}" />
+                                                    </ToolTip>
+                                                </TextBlock.ToolTip>
+                                            </TextBlock>
+                                        </StackPanel>
+                                    </DataTemplate>
+                                </GridViewColumn.CellTemplate>
+                            </GridViewColumn>
+                            <GridViewColumn
+    x:Name="SizeHeader"
+    Width="80"
+    Header="Size">
+                                <GridViewColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock Text="{Binding Size}" TextTrimming="CharacterEllipsis">
+                                            <TextBlock.ToolTip>
+                                                <ToolTip>
+                                                    <TextBlock Text="{Binding Size}" />
+                                                </ToolTip>
+                                            </TextBlock.ToolTip>
+                                            
+                                        </TextBlock>
+                                    </DataTemplate>
+                                </GridViewColumn.CellTemplate>
+                            </GridViewColumn>
+                            <GridViewColumn
+    x:Name="PathHeader"
+    Width="250"
+    Header="Path">
+                                <GridViewColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center"
+                Text="{Binding Path}"
+                TextAlignment="Left" TextTrimming="CharacterEllipsis">
+                                            <TextBlock.ToolTip>
+                                                <ToolTip>
+                                                    <TextBlock Text="{Binding Path}" />
+                                                </ToolTip>
+                                            </TextBlock.ToolTip>
+                                        </TextBlock>
+                                    </DataTemplate>
+                                </GridViewColumn.CellTemplate>
+                            </GridViewColumn>
+
+                            <GridViewColumn
+    x:Name="ProgressHeader"
+    Width="50"
+    Header="Progress">
+                                <GridViewColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock Text="{Binding Progress}" />
+                                    </DataTemplate>
+                                </GridViewColumn.CellTemplate>
+                            </GridViewColumn>
+                        </GridView>
+                    </ListView.View>
+                </ListView>
+                <WrapPanel Margin="0,12,0,0">
+                    <Button
+                        Margin="12,0,0,0"
+            Name="btnRemove"
+            MinWidth="112"
+            Padding="8,0,8,0"
+            Height="32"
+            Click="btnRemove_Click"
+            Content="Delete"
+                        BorderBrush="#33000000" Background="#E1E1E1" BorderThickness="1"  Style="{StaticResource DisabledButtonStyle}"
+             />
+                    <Button
+Name="btnMoveUp"
+Width="150"
+Height="32"
+Margin="10,5"
+Content="MoveUp"
+IsEnabled="False" Style="{StaticResource DisabledButtonStyle}"
+BorderBrush="#33000000" Background="#E1E1E1" BorderThickness="1" Click="btnMoveUp_Click" Visibility="Collapsed"/>
+                    <Button
+            Name="btnMoveDown"
+            Width="150"
+            Height="32"
+            Margin="10,5"
+            Content="Move Down"
+            IsEnabled="False"
+            BorderBrush="#33000000" Background="#E1E1E1" BorderThickness="1" Click="btnMoveDown_Click" Style="{StaticResource DisabledButtonStyle}"  Visibility="Collapsed"/>
+
+                </WrapPanel>
+            </StackPanel>
+            <GroupBox
+                Grid.Row="0"
+                Grid.RowSpan="2"
+                Grid.Column="1"
+                Margin="8,40,20,0"
+     Name="groupBox1"
+     Width="200"
+     Height="262"
+                VerticalAlignment="Top">
+                <GroupBox.Header>
+                    <TextBlock Name="groupBox1Text" Text="Optimization Quality" FontWeight="DemiBold"></TextBlock>
+                </GroupBox.Header>
+                <StackPanel>
+                    <RadioButton
+             Name="rbtnLow"
+             Margin="8,8,0,0"
+             Checked="rbtnAllPage_Checked"
+             Content="Low"
+             GroupName="GroupPageRange" Style="{StaticResource BigCustomRadioButtonStyle}"/>
+                    <RadioButton
+             Name="rbtnMedium"
+             Margin="8,8"
+             Checked="rbtnCurrentPage_Checked"
+             Content="Medium"
+             GroupName="GroupPageRange" Style="{StaticResource BigCustomRadioButtonStyle}"/>
+                    <RadioButton
+             Name="rbtnHigh"
+             Margin="8,0"
+             Checked="rbtnOldPageOnly_Checked"
+             Content="High"
+             GroupName="GroupPageRange" Style="{StaticResource BigCustomRadioButtonStyle}"/>
+                    <StackPanel Orientation="Horizontal">
+                        <RadioButton
+				 Name="rbtnCustom"
+				 Margin="8,8"
+				 Checked="RbtnEvenPageOnly_Checked"
+				 Content="Custom"
+				 GroupName="GroupPageRange" Style="{StaticResource BigCustomRadioButtonStyle}"/>
+                        <StackPanel Orientation="Horizontal" IsEnabled="{Binding ElementName=rbtnCustom,Path=IsChecked}">
+                            <TextBox Name="txtQuality" Width="50" Height="28"  PreviewTextInput="TextBox_PreviewTextInput" TextChanged="TextBox_TextChanged" InputMethod.IsInputMethodEnabled="False" Padding="0,5,0,0" Text="100"></TextBox>
+                            <TextBlock Height="15" Margin="8,0,0,0">%</TextBlock>
+                        </StackPanel>
+                    </StackPanel>
+                </StackPanel>
+            </GroupBox>
+            <WrapPanel
+    Width="300"
+    HorizontalAlignment="Right"
+    DockPanel.Dock="Right" Grid.Row="2" Grid.ColumnSpan="2">
+                <Button
+        Name="btnCompress"
+                    Style="{StaticResource DisabledButtonStyle}"
+        BorderBrush="#FA477EDE" Background="#E1E1E1" BorderThickness="1"
+        MinWidth="112"
+Padding="8,0,8,0"
+        Height="32"
+        Margin="30,0,2,0"
+        HorizontalAlignment="Right"
+        VerticalContentAlignment="Center"
+        IsEnabled="False"
+        Click="btnCompress_Click">
+                    Compress
+                </Button>
+                <Button
+        Name="btnCancel"
+        MinWidth="112"
+Padding="8,0,8,0"
+        Height="32"
+        Margin="10,0,10,0"
+        HorizontalAlignment="Right"
+        VerticalContentAlignment="Center"
+        Click="btnCancel_Click" Style="{StaticResource DisabledButtonStyle}"
+        BorderBrush="#33000000" Background="#E1E1E1" BorderThickness="1">
+                    Cancel
+                </Button>
+            </WrapPanel>
+        </Grid>
+    </Grid>
+</Window>

+ 778 - 0
Demo/Examples/Compdfkit.Controls/Compress/CompressDialog.xaml.cs

@@ -0,0 +1,778 @@
+using ComPDFKit.Controls.Common;
+using ComPDFKit.Controls.Helper;
+using ComPDFKit.PDFDocument;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Drawing;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Forms;
+using System.Windows.Input;
+using System.Windows.Interop;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using DragEventArgs = System.Windows.DragEventArgs;
+using Microsoft.WindowsAPICodePack.Dialogs;
+using System.Threading.Tasks;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace ComPDFKit.Controls.Compress
+{
+    public partial class CompressDialog : Window
+    {
+        private CPDFDocument tempDocument;
+        private List<string> pathlist = new List<string>();
+        private float quality = 45;
+        private int compressindex = -1;
+        private IntPtr compressingIntpr = IntPtr.Zero;
+        private string compressingfilepath = "";
+        private CPDFDocument.GetPageIndexDelegate indexDelegate = null;
+        private delegate void RefreshPageIndex(int pageIndex);
+        private bool stopClose = false;
+        private bool isCanceled = false;
+
+        public ObservableCollection<CompressDataItem> CompressDatas { get; set; }
+        
+        public CompressDialog()
+        {
+            InitializeComponent();
+            SetLangText();
+            rbtnMedium.IsChecked = true;
+            CompressDatas = new ObservableCollection<CompressDataItem>();
+            CompressListView.ItemsSource = CompressDatas;
+        }
+
+        private BitmapSource GetImagePath(string filePath, out IntPtr bitmapHandle)
+        {
+            try
+            {
+                Icon ico = System.Drawing.Icon.ExtractAssociatedIcon(filePath);
+                Bitmap bitmap = ico.ToBitmap();
+
+                bitmapHandle = bitmap.GetHbitmap();
+                BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(bitmapHandle, IntPtr.Zero, System.Windows.Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
+                return bitmapSource;
+            }
+            catch
+            {
+                bitmapHandle = IntPtr.Zero;
+                return null;
+            }
+        }
+
+        private void SetLangText()
+        {
+            this.Title = LanguageHelper.CompressManager.GetString("CompressStr");
+            btnAddFile.Content = LanguageHelper.CompressManager.GetString("Main_AddFile");
+
+            btnRemove.Content = LanguageHelper.CompressManager.GetString("Main_RemoveAll");
+            btnMoveUp.Content = LanguageHelper.CompressManager.GetString("Merge_MoveUp");
+            btnMoveDown.Content = LanguageHelper.CompressManager.GetString("Merge_MoveDown");
+            btnCompress.Content = LanguageHelper.CompressManager.GetString("CompressStr");
+            btnCancel.Content = LanguageHelper.CompressManager.GetString("Main_Cancel");
+
+            groupBox1Text.Text = LanguageHelper.CompressManager.GetString("Compress_OptimizationQuality");
+            rbtnLow.Content = LanguageHelper.CompressManager.GetString("Compress_Low");
+            rbtnMedium.Content = LanguageHelper.CompressManager.GetString("Compress_Medium");
+            rbtnMedium.IsChecked = true;
+            rbtnHigh.Content = LanguageHelper.CompressManager.GetString("Compress_High");
+            rbtnCustom.Content = LanguageHelper.CompressManager.GetString("Compress_Custom");
+
+            PathHeader.Header = LanguageHelper.CompressManager.GetString("FileInfo_Location");
+            ProgressHeader.Header = LanguageHelper.CompressManager.GetString("Convert_Progress");
+            FileName.Header = LanguageHelper.CompressManager.GetString("Main_FileName");
+            SizeHeader.Header = LanguageHelper.CompressManager.GetString("FileInfo_Size");
+
+            lbTotalFiles.Content = string.Format(LanguageHelper.CompressManager.GetString("Merge_TotalPage"), 0);
+        }
+
+        private void btnAddFile_Click(object sender, RoutedEventArgs e)
+        {
+            OpenFileDialog file = new OpenFileDialog();
+            file.Multiselect = true;
+            file.Filter = "PDF Files (*.pdf)|*.pdf";
+            if (file.ShowDialog() == System.Windows.Forms.DialogResult.OK)
+            {
+                var files = file.FileNames;
+                for (int i = 0; i < files.Length; i++)
+                {
+                    AddFiletoList(files[i]);
+                }
+
+                UpdateMoveButtonState();
+            }
+        }
+
+        private void AddFiletoList(string filePath)
+        {
+            string password = "";
+            if (pathlist.Contains(filePath) || Path.GetExtension(filePath).ToLower() != ".pdf")
+            {
+                return;
+            }
+
+            CPDFDocument doc = CPDFDocument.InitWithFilePath(filePath);
+            if (doc == null)
+            {
+                MessageBoxEx.Show(LanguageHelper.CompressManager.GetString("Main_OpenFileFailedWarning"));
+                return;
+            }
+
+            if (doc.IsLocked)
+            {
+                PasswordWindow passwordWindow = new PasswordWindow();
+                passwordWindow.InitDocument(doc);
+                passwordWindow.Owner = Window.GetWindow(this);
+                passwordWindow.PasswordDialog.SetShowText(filePath + " is encrypted.");
+                passwordWindow.ShowDialog();
+                if (doc.IsLocked)
+                {
+                    doc.Release();
+                    return;
+                }
+
+                password = passwordWindow.Password;
+            }
+
+            pathlist.Add(filePath);
+            BitmapSource bitmapSource = GetImagePath(doc.FilePath, out IntPtr bitmapHandle);
+            CompressDataItem newdata = new CompressDataItem()
+            {
+                Name = doc.FileName,
+                Size = CommonHelper.GetFileSize(filePath),
+                Progress = "0/" + doc.PageCount,
+                Path = doc.FilePath,
+                PageCount = doc.PageCount,
+                ImagePath = bitmapSource
+
+            };
+            AddListViewItem(newdata, password);
+            doc.Release();
+            UpdateTotalCount();
+        }
+
+        private void UpdateTotalCount()
+        {
+            lbTotalFiles.Content = string.Format(LanguageHelper.CompressManager.GetString("Merge_TotalPage"), CompressListView.Items.Count);
+            if (CompressListView.Items.Count == 0)
+                btnCompress.IsEnabled = false;
+            else
+                btnCompress.IsEnabled = true;
+        }
+
+        private void AddListViewItem(CompressDataItem data, string password)
+        {
+            if (!string.IsNullOrEmpty(password))
+                data.PassWord = password;
+
+            CompressDatas.Add(data);
+            UpdateTotalCount();
+        }
+
+        private void btnRemove_Click(object sender, RoutedEventArgs e)
+        {
+            if (CompressListView.SelectedItems.Count > 0)
+            {
+                List<int> pages = new List<int>();
+                foreach (var selectedItem in CompressListView.SelectedItems)
+                {
+                    var imageItem = (CompressDataItem)selectedItem;
+                    int index = CompressListView.Items.IndexOf(imageItem);
+                    pages.Add(index);
+                }
+                pages.Sort();
+
+                for (int i = pages.Count - 1; i >= 0; i--)
+                {
+                    int index = pages[i];
+                    string path = ((CompressDataItem)CompressListView.Items[index]).Path;
+                    pathlist.Remove(path);
+                    CompressDatas.RemoveAt(index);
+                }
+            }
+            else
+            {
+                CompressDatas.Clear();
+                pathlist.Clear();
+            }
+            UpdateTotalCount();
+        }
+
+        private void btnChoosePage_Click(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        private async void btnCompress_Click(object sender, RoutedEventArgs e)
+        {
+            if ((bool)rbtnLow.IsChecked)
+                quality = 10;
+            else if ((bool)rbtnMedium.IsChecked)
+                quality = 40;
+            else if ((bool)rbtnHigh.IsChecked)
+                quality = 80;
+            else
+            {
+                int q = 0;
+                bool r = int.TryParse(txtQuality.Text, out q);
+                if (!r || q > 100 || q < 0)
+                {
+                    MessageBoxEx.Show(LanguageHelper.CompressManager.GetString("Compress_NumberErrorWarning"));
+                    txtQuality.Focus();
+                    return;
+                }
+                quality = q;
+            }
+
+            CommonOpenFileDialog commonFileDialog = new CommonOpenFileDialog(LanguageHelper.CompressManager.GetString("Main_OpenFolderNoteWarning"));
+            commonFileDialog.IsFolderPicker = true;
+            if (commonFileDialog.ShowDialog() == CommonFileDialogResult.Ok)
+            {
+                if (string.IsNullOrEmpty(commonFileDialog.FileName))
+                {
+                    MessageBoxEx.Show(LanguageHelper.CompressManager.GetString("Main_NoSelectedFilesWarning"),
+                        LanguageHelper.CompressManager.GetString("Main_HintWarningTitle"),
+                        MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
+                    return;
+                }
+            }
+            else
+                return;
+
+            stopClose = true;
+            groupBox1.IsEnabled = false;
+            btnAddFile.IsEnabled = false;
+            btnCompress.IsEnabled = false;
+            btnRemove.Content = LanguageHelper.CompressManager.GetString("Main_RemoveAll");
+            btnRemove.IsEnabled = false;
+            btnMoveDown.IsEnabled = false;
+            btnMoveUp.IsEnabled = false;
+            bool isFailed = false;
+            string selectedFile = "";
+            for (int i = 0; i < CompressListView.Items.Count; i++)
+            {
+                var item = (CompressDataItem)CompressListView.Items[i];
+                string path = item.Path;
+                if (isCanceled)
+                {
+                    item.Progress = LanguageHelper.CompressManager.GetString("Main_Interrupt");
+                    continue;
+                }
+
+                CPDFDocument doc = CPDFDocument.InitWithFilePath(path);
+                if (doc.IsLocked && item.PassWord != null && !string.IsNullOrEmpty(item.PassWord))
+                {
+                    doc.UnlockWithPassword(item.PassWord.ToString());
+                }
+
+                var filename = doc.FileName + " compressed";
+                var filepath = commonFileDialog.FileName + "\\" + filename + ".pdf";
+                filepath = CommonHelper.CreateFilePath(filepath);
+                selectedFile = compressingfilepath = filepath;
+
+                indexDelegate += GetIndex;
+                compressingIntpr = doc.CompressFile_Init(quality, indexDelegate);
+                GC.KeepAlive(indexDelegate);
+                compressindex = i;
+                tempDocument = doc;
+                var r = await Task.Run<bool>(() => { return doc.CompressFile_Start(compressingIntpr, filepath); });
+                if (!r)
+                {
+                    item.Progress = LanguageHelper.CompressManager.GetString("Main_FailedState");
+                    doc.Release();
+                    if (File.Exists(filepath))
+                        File.Delete(filepath);
+                    isFailed = true;
+                    continue;
+                }
+                compressingfilepath = "";
+                doc.Release();
+            }
+
+            int itemCount = CompressListView.Items.Count;
+            if (!isFailed)
+            {
+                System.Diagnostics.Process.Start("explorer", "/select,\"" + selectedFile + "\"");
+            }
+
+            isCanceled = false;
+            compressindex = -1;
+            stopClose = false;
+            btnAddFile.IsEnabled = true;
+            btnCompress.IsEnabled = true;
+            btnRemove.Content = LanguageHelper.CompressManager.GetString("Main_Delete");
+            btnRemove.IsEnabled = true;
+            btnMoveDown.IsEnabled = true;
+            btnMoveUp.IsEnabled = true;
+            groupBox1.IsEnabled = true;
+        }
+
+        private int GetIndex(int pageindex)
+        {
+            try
+            {
+                if (Dispatcher.CheckAccess() == false)
+                {
+                    return Dispatcher.Invoke(new CPDFDocument.GetPageIndexDelegate(delegate (int s)
+                    {
+                        if (CompressListView.Items.Count >= compressindex)
+                        {
+                            if (CompressListView.Items[compressindex] is CompressDataItem dataItem)
+                            {
+                                dataItem.Progress = pageindex + "/" + dataItem.PageCount;
+                                if (pageindex == dataItem.PageCount - 1)
+                                {
+                                    dataItem.Progress = LanguageHelper.CompressManager.GetString("Main_CompletedState");
+                                }
+                            }
+                        }
+                        return 0;
+                    }), pageindex).ToString().Length;
+                }
+                else
+                {
+                    if (CompressListView.Items.Count >= compressindex)
+                    {
+                        if (CompressListView.Items[compressindex] is CompressDataItem dataItem)
+                        {
+                            dataItem.Progress = pageindex + "/" + dataItem.PageCount;
+                            if (pageindex == dataItem.PageCount - 1)
+                            {
+                                dataItem.Progress = LanguageHelper.CompressManager.GetString("Main_CompletedState");
+                            }
+                        }
+                    }
+                    return 0;
+                }
+            }
+            catch { return -1; }
+        }
+
+        private void btnCancel_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                if (compressindex != -1 && !compressingIntpr.Equals(IntPtr.Zero))
+                {
+                    if (MessageBoxEx.Show(LanguageHelper.CompressManager.GetString("CompressInterruptWarning"), "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes && tempDocument != null)
+                    {
+                        tempDocument.CompressFile_Cancel(compressingIntpr);
+                        isCanceled = true;
+                        if (File.Exists(compressingfilepath))
+                            File.Delete(compressingfilepath);
+                    }
+                }
+                else
+                {
+                    this.Close();
+                    this.DialogResult = false;
+                }
+            }
+            catch { }
+        }
+
+        private void ConverterListView_DragOver(object sender, DragEventArgs e)
+        {
+            var files = (Array)e.Data.GetData(System.Windows.DataFormats.FileDrop);
+            int count = 0;
+            string pdf = "pdf";
+            foreach (string file in files)
+            {
+                string text = Path.GetExtension(file);
+                if (text.IndexOf(pdf, StringComparison.OrdinalIgnoreCase) >= 0)
+                {
+                    count++;
+                }
+            }
+            if (count < 1)
+            {
+                e.Effects = System.Windows.DragDropEffects.None;
+                Mouse.SetCursor(System.Windows.Input.Cursors.No);
+            }
+            else
+            {
+                e.Effects = System.Windows.DragDropEffects.Copy;
+                Mouse.SetCursor(System.Windows.Input.Cursors.Arrow);
+            }
+
+            return;
+        }
+
+        private void ConverterListView_Drop(object sender, DragEventArgs e)
+        {
+            var files = (Array)e.Data.GetData(System.Windows.DataFormats.FileDrop);
+            if (files != null && files.Length > 0)
+            {
+                var Files = (string[])files;
+                for (int i = 0; i < Files.Length; i++)
+                {
+                    AddFiletoList(Files[i]);
+                }
+            }
+        }
+
+        private void ConverterListView_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
+        {
+
+        }
+
+        private void ConverterListView_PreviewMouseUp(object sender, MouseButtonEventArgs e)
+        {
+            DependencyObject element = (DependencyObject)e.OriginalSource;
+            if (element is Thumb thumb)
+            {
+                GridViewColumnHeader gridViewColumnHeader = CommonHelper.ViewportHelper.FindVisualParent<GridViewColumnHeader>(thumb);
+                if (gridViewColumnHeader != null && gridViewColumnHeader.Content != null)
+                {
+                    GridViewColumn column = FindGridViewColumn(gridViewColumnHeader.Content.ToString(), CompressListView);
+                    if (column != null)
+                    {
+                        if (column.Header == LanguageHelper.CompressManager.GetString("Main_FileName") && column.ActualWidth > 240)
+                        {
+                            TextBlock textBlock = FindTextBlockInCellTemplate(column);
+                            if (textBlock != null)
+                            {
+                                textBlock.MaxWidth = textBlock.Width = column.ActualWidth - 20;
+                                TxbName_SizeChanged(textBlock, null);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private TextBlock FindTextBlockInCellTemplate(GridViewColumn column)
+        {
+            DataTemplate dataTemplate = column.CellTemplate;
+            if (dataTemplate != null)
+            {
+                FrameworkElement frameworkElement = dataTemplate.LoadContent() as FrameworkElement;
+                if (frameworkElement != null)
+                {
+                    return CommonHelper.ViewportHelper.FindVisualChild<TextBlock>(frameworkElement);
+                }
+            }
+
+            return null;
+        }
+
+        private GridViewColumn FindGridViewColumn(string columnHeader, System.Windows.Controls.ListView listView)
+        {
+            GridView gridView = listView.View as GridView;
+            if (gridView != null)
+            {
+                foreach (var column in gridView.Columns)
+                {
+                    GridViewColumn gvColumn = column as GridViewColumn;
+                    if (gvColumn != null && gvColumn.Header.ToString() == columnHeader)
+                    {
+                        return gvColumn;
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        private void UpdateMoveButtonState()
+        {
+            if (compressindex != -1 && !compressingIntpr.Equals(IntPtr.Zero))
+            {
+                return;
+            }
+
+            if (CompressListView.Items.Count > 0 && CompressListView.SelectedItems.Count > 0)
+            {
+                btnRemove.Content = LanguageHelper.CompressManager.GetString("Main_Delete"); ;
+                int count = CompressListView.Items.Count;
+                if (CompressListView.SelectedItems.Contains(CompressListView.Items[CompressListView.Items.Count - 1]))
+                {
+                    btnMoveDown.IsEnabled = false;
+                }
+                else
+                    btnMoveDown.IsEnabled = true;
+                if (CompressListView.SelectedItems.Contains(CompressListView.Items[0]))
+                    btnMoveUp.IsEnabled = false;
+                else
+                    btnMoveUp.IsEnabled = true;
+            }
+            else
+            {
+                btnRemove.Content = LanguageHelper.CompressManager.GetString("Main_RemoveAll");
+                btnMoveDown.IsEnabled = false;
+                btnMoveUp.IsEnabled = false;
+            }
+        }
+
+        private void ConverterListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            UpdateMoveButtonState();
+        }
+        private void UpdateColumnsWidth(System.Windows.Controls.ListView listView)
+        {
+            int autoFillColumnIndex = (listView.View as System.Windows.Controls.GridView).Columns.Count - 1;
+            if (listView.ActualWidth == Double.NaN)
+            {
+                listView.Measure(new System.Windows.Size(Double.PositiveInfinity, Double.PositiveInfinity));
+            }
+            double remainingSpace = listView.ActualWidth;
+            for (int i = 0; i < (listView.View as System.Windows.Controls.GridView).Columns.Count; i++)
+            {
+                if (i != autoFillColumnIndex)
+                {
+                    remainingSpace -= (listView.View as System.Windows.Controls.GridView).Columns[i].ActualWidth;
+                    (listView.View as System.Windows.Controls.GridView).Columns[autoFillColumnIndex].Width = remainingSpace >= 0 ? remainingSpace : 0;
+                }
+            }
+        }
+
+        private void ConverterListView_Loaded(object sender, RoutedEventArgs e)
+        {
+            UpdateColumnsWidth(sender as System.Windows.Controls.ListView);
+        }
+
+        private void ConverterListView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
+        {
+            var pos = e.GetPosition(CompressListView);
+            var result = VisualTreeHelper.HitTest(CompressListView, pos);
+            if (result != null)
+            {
+                var listBoxItem = CommonHelper.ViewportHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
+                if (listBoxItem == null)
+                {
+                    CompressListView.SelectedItems.Clear();
+                }
+            }
+            CompressListView.Focus();
+        }
+
+        private void ConverterListView_SizeChanged(object sender, SizeChangedEventArgs e)
+        {
+            UpdateColumnsWidth(sender as System.Windows.Controls.ListView);
+        }
+
+        private void TxbName_SizeChanged(object sender, SizeChangedEventArgs e)
+        {
+
+        }
+
+        private void PART_HeaderGripper_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
+        {
+
+        }
+
+        private void rbtnAllPage_Checked(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        private void rbtnCurrentPage_Checked(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        private void rbtnOldPageOnly_Checked(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        private void RbtnEvenPageOnly_Checked(object sender, RoutedEventArgs e)
+        {
+
+        }
+
+        public class CompressDataItem : INotifyPropertyChanged
+        {
+            public event PropertyChangedEventHandler PropertyChanged;
+
+            protected virtual void OnPropertyChanged(string propertyName)
+            {
+                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+            }
+
+            private string passWord;
+
+            public string PassWord { get; set; }
+
+            public BitmapSource ImagePath { get; set; }
+
+            public string Name { get; set; }
+            public string Size { get; set; }
+
+            public string Path { get; set; }
+            public int PageCount { get; set; }
+
+            private string progress;
+
+            public string Progress
+            {
+                get { return progress; }
+                set
+                {
+                    progress = value;
+                    OnPropertyChanged("Progress");
+                }
+            }
+        }
+
+        private void btnMoveDown_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                var items = CompressListView.SelectedItems;
+                if (items.Count > 0)
+                {
+                    List<int> indexs = new List<int>();
+                    foreach (var selectedItem in CompressListView.SelectedItems)
+                    {
+                        var imageItem = (CompressDataItem)selectedItem;
+                        int index = CompressListView.Items.IndexOf(imageItem);
+                        indexs.Add(index);
+                    }
+
+                    indexs.Sort();
+                    for (int i = 0; i < indexs.Count; i++)
+                    {
+                        var index = indexs[indexs.Count - 1 - i];
+                        var item = CompressDatas[index];
+                        CompressDatas.RemoveAt(index);
+                        CompressDatas.Insert(index + 1, item);
+                    }
+
+                    CompressListView.SelectedItems.Clear();
+
+                    for (int i = 0; i < indexs.Count; i++)
+                    {
+                        CompressListView.SelectedItems.Add(CompressListView.Items[indexs[i] + 1]);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+            }
+        }
+
+        private void btnMoveUp_Click(object sender, RoutedEventArgs e)
+        {
+            try
+            {
+                var items = CompressListView.SelectedItems; 
+                if (items.Count > 0)
+                {
+                    List<int> indexs = new List<int>();
+                    foreach (var selectedItem in CompressListView.SelectedItems)
+                    {
+                        var imageItem = (CompressDataItem)selectedItem;
+                        int index = CompressListView.Items.IndexOf(imageItem);
+                        indexs.Add(index);
+                    }
+                    indexs.Sort();
+
+                    for (int i = 0; i < indexs.Count; i++)
+                    {
+                        var index = indexs[i];
+                        var item = CompressDatas[index];
+                        CompressDatas.RemoveAt(index);
+                        CompressDatas.Insert(index - 1, item);
+                    }
+
+                    CompressListView.SelectedItems.Clear();
+
+                    for (int i = 0; i < indexs.Count; i++)
+                    {
+                        CompressListView.SelectedItems.Add(CompressListView.Items[indexs[i] - 1]);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+
+            }
+        }
+
+        private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
+        {
+            Regex regex = new Regex("[^0-9]+");
+            if (regex.IsMatch(e.Text))
+            {
+                e.Handled = true;
+            }
+        }
+
+        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (sender is System.Windows.Controls.TextBox textBox)
+            {
+                if (!string.IsNullOrEmpty(textBox.Text))
+                {
+                    int value = int.Parse(textBox.Text);
+
+                    if (value < 1)
+                    {
+                        textBox.Text = "1";
+                        textBox.Select(textBox.Text.Length, 0);
+                    }
+                    else if (value > 100)
+                    {
+                        textBox.Text = "100";
+                        textBox.Select(textBox.Text.Length, 0);
+                    }
+                }
+                else
+                {
+                    textBox.Text = "1";
+                    textBox.Select(textBox.Text.Length, 0);
+                }
+            }
+        }
+    }
+
+    public class MaxWidthToTextTrimmingConverter : IMultiValueConverter
+    {
+        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (values.Length == 2 && values[0] is double maxWidth && values[1] is string text)
+            {
+                if (maxWidth >= MeasureTextWidth(text))
+                {
+                    return TextTrimming.None;
+                }
+                else
+                {
+                    return TextTrimming.CharacterEllipsis;
+                }
+            }
+
+            return TextTrimming.None;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotSupportedException();
+        }
+
+        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        private double MeasureTextWidth(string text)
+        {
+            var formattedText = new FormattedText(
+            text,
+            CultureInfo.CurrentCulture,
+            System.Windows.FlowDirection.LeftToRight,
+            new Typeface("Arial"),
+            12,
+            System.Windows.Media.Brushes.Black);
+
+            return formattedText.WidthIncludingTrailingWhitespace;
+        }
+    }
+}

+ 405 - 0
Demo/Examples/Compdfkit.Controls/Strings/Compress.Designer.cs

@@ -0,0 +1,405 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace ComPDFKit.Controls.Strings {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Compress {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Compress() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ComPDFKit.Controls.Strings.Compress", typeof(Compress).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Custom.
+        /// </summary>
+        internal static string Compress_Custom {
+            get {
+                return ResourceManager.GetString("Compress_Custom", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to High.
+        /// </summary>
+        internal static string Compress_High {
+            get {
+                return ResourceManager.GetString("Compress_High", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Low.
+        /// </summary>
+        internal static string Compress_Low {
+            get {
+                return ResourceManager.GetString("Compress_Low", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Medium.
+        /// </summary>
+        internal static string Compress_Medium {
+            get {
+                return ResourceManager.GetString("Compress_Medium", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The file size entered is incorrect, try again please.
+        /// </summary>
+        internal static string Compress_NumberErrorWarning {
+            get {
+                return ResourceManager.GetString("Compress_NumberErrorWarning", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Compress files succeeded!.
+        /// </summary>
+        internal static string Compress_OKWarning {
+            get {
+                return ResourceManager.GetString("Compress_OKWarning", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Optimization Options.
+        /// </summary>
+        internal static string Compress_OptimizationQuality {
+            get {
+                return ResourceManager.GetString("Compress_OptimizationQuality", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure to stop the compressing?.
+        /// </summary>
+        internal static string CompressInterruptWarning {
+            get {
+                return ResourceManager.GetString("CompressInterruptWarning", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Compress.
+        /// </summary>
+        internal static string CompressStr {
+            get {
+                return ResourceManager.GetString("CompressStr", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Undo.
+        /// </summary>
+        internal static string ContentSelection_CancelDo {
+            get {
+                return ResourceManager.GetString("ContentSelection_CancelDo", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Exit.
+        /// </summary>
+        internal static string ContentSelection_Exit {
+            get {
+                return ResourceManager.GetString("ContentSelection_Exit", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Output.
+        /// </summary>
+        internal static string ContentSelection_Output {
+            get {
+                return ResourceManager.GetString("ContentSelection_Output", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Progress.
+        /// </summary>
+        internal static string Convert_Progress {
+            get {
+                return ResourceManager.GetString("Convert_Progress", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Select Area.
+        /// </summary>
+        internal static string Corp_Customize {
+            get {
+                return ResourceManager.GetString("Corp_Customize", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The page cannot be restored to original state after you have cropped it. Are you sure you want to crop the page?.
+        /// </summary>
+        internal static string Corp_Customize_PRM {
+            get {
+                return ResourceManager.GetString("Corp_Customize_PRM", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Location.
+        /// </summary>
+        internal static string FileInfo_Location {
+            get {
+                return ResourceManager.GetString("FileInfo_Location", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Size.
+        /// </summary>
+        internal static string FileInfo_Size {
+            get {
+                return ResourceManager.GetString("FileInfo_Size", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Add Files.
+        /// </summary>
+        internal static string Main_AddFile {
+            get {
+                return ResourceManager.GetString("Main_AddFile", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Cancel.
+        /// </summary>
+        internal static string Main_Cancel {
+            get {
+                return ResourceManager.GetString("Main_Cancel", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Completed.
+        /// </summary>
+        internal static string Main_CompletedState {
+            get {
+                return ResourceManager.GetString("Main_CompletedState", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Copy.
+        /// </summary>
+        internal static string Main_Copy {
+            get {
+                return ResourceManager.GetString("Main_Copy", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Crop.
+        /// </summary>
+        internal static string Main_Crop {
+            get {
+                return ResourceManager.GetString("Main_Crop", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Delete.
+        /// </summary>
+        internal static string Main_Delete {
+            get {
+                return ResourceManager.GetString("Main_Delete", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Failed.
+        /// </summary>
+        internal static string Main_FailedState {
+            get {
+                return ResourceManager.GetString("Main_FailedState", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to File Name.
+        /// </summary>
+        internal static string Main_FileName {
+            get {
+                return ResourceManager.GetString("Main_FileName", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Hint.
+        /// </summary>
+        internal static string Main_HintWarningTitle {
+            get {
+                return ResourceManager.GetString("Main_HintWarningTitle", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Interrupt.
+        /// </summary>
+        internal static string Main_Interrupt {
+            get {
+                return ResourceManager.GetString("Main_Interrupt", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to About Us.
+        /// </summary>
+        internal static string Main_MenuHelp_About {
+            get {
+                return ResourceManager.GetString("Main_MenuHelp_About", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to No.
+        /// </summary>
+        internal static string Main_No {
+            get {
+                return ResourceManager.GetString("Main_No", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to No file selected.
+        /// </summary>
+        internal static string Main_NoSelectedFilesWarning {
+            get {
+                return ResourceManager.GetString("Main_NoSelectedFilesWarning", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to OK.
+        /// </summary>
+        internal static string Main_Ok {
+            get {
+                return ResourceManager.GetString("Main_Ok", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Please select a folder.
+        /// </summary>
+        internal static string Main_OpenFolderNoteWarning {
+            get {
+                return ResourceManager.GetString("Main_OpenFolderNoteWarning", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Print.
+        /// </summary>
+        internal static string Main_Print {
+            get {
+                return ResourceManager.GetString("Main_Print", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Remove All Files.
+        /// </summary>
+        internal static string Main_RemoveAll {
+            get {
+                return ResourceManager.GetString("Main_RemoveAll", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Yes.
+        /// </summary>
+        internal static string Main_Yes {
+            get {
+                return ResourceManager.GetString("Main_Yes", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Move Down.
+        /// </summary>
+        internal static string Merge_MoveDown {
+            get {
+                return ResourceManager.GetString("Merge_MoveDown", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Move Up.
+        /// </summary>
+        internal static string Merge_MoveUp {
+            get {
+                return ResourceManager.GetString("Merge_MoveUp", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} file(s) in total.
+        /// </summary>
+        internal static string Merge_TotalPage {
+            get {
+                return ResourceManager.GetString("Merge_TotalPage", resourceCulture);
+            }
+        }
+    }
+}

+ 234 - 0
Demo/Examples/Compdfkit.Controls/Strings/Compress.resx

@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="CompressInterruptWarning" xml:space="preserve">
+    <value>Are you sure to stop the compressing?</value>
+  </data>
+  <data name="CompressStr" xml:space="preserve">
+    <value>Compress</value>
+  </data>
+  <data name="Compress_Custom" xml:space="preserve">
+    <value>Custom</value>
+  </data>
+  <data name="Compress_High" xml:space="preserve">
+    <value>High</value>
+  </data>
+  <data name="Compress_Low" xml:space="preserve">
+    <value>Low</value>
+  </data>
+  <data name="Compress_Medium" xml:space="preserve">
+    <value>Medium</value>
+  </data>
+  <data name="Compress_NumberErrorWarning" xml:space="preserve">
+    <value>The file size entered is incorrect, try again please</value>
+  </data>
+  <data name="Compress_OKWarning" xml:space="preserve">
+    <value>Compress files succeeded!</value>
+  </data>
+  <data name="Compress_OptimizationQuality" xml:space="preserve">
+    <value>Optimization Options</value>
+  </data>
+  <data name="ContentSelection_CancelDo" xml:space="preserve">
+    <value>Undo</value>
+  </data>
+  <data name="ContentSelection_Exit" xml:space="preserve">
+    <value>Exit</value>
+  </data>
+  <data name="ContentSelection_Output" xml:space="preserve">
+    <value>Output</value>
+  </data>
+  <data name="Convert_Progress" xml:space="preserve">
+    <value>Progress</value>
+  </data>
+  <data name="Corp_Customize" xml:space="preserve">
+    <value>Select Area</value>
+  </data>
+  <data name="Corp_Customize_PRM" xml:space="preserve">
+    <value>The page cannot be restored to original state after you have cropped it. Are you sure you want to crop the page?</value>
+  </data>
+  <data name="FileInfo_Location" xml:space="preserve">
+    <value>Location</value>
+  </data>
+  <data name="FileInfo_Size" xml:space="preserve">
+    <value>Size</value>
+  </data>
+  <data name="Main_AddFile" xml:space="preserve">
+    <value>Add Files</value>
+  </data>
+  <data name="Main_Cancel" xml:space="preserve">
+    <value>Cancel</value>
+  </data>
+  <data name="Main_CompletedState" xml:space="preserve">
+    <value>Completed</value>
+  </data>
+  <data name="Main_Copy" xml:space="preserve">
+    <value>Copy</value>
+  </data>
+  <data name="Main_Crop" xml:space="preserve">
+    <value>Crop</value>
+  </data>
+  <data name="Main_Delete" xml:space="preserve">
+    <value>Delete</value>
+  </data>
+  <data name="Main_FailedState" xml:space="preserve">
+    <value>Failed</value>
+  </data>
+  <data name="Main_FileName" xml:space="preserve">
+    <value>File Name</value>
+  </data>
+  <data name="Main_HintWarningTitle" xml:space="preserve">
+    <value>Hint</value>
+  </data>
+  <data name="Main_Interrupt" xml:space="preserve">
+    <value>Interrupt</value>
+  </data>
+  <data name="Main_MenuHelp_About" xml:space="preserve">
+    <value>About Us</value>
+  </data>
+  <data name="Main_No" xml:space="preserve">
+    <value>No</value>
+  </data>
+  <data name="Main_NoSelectedFilesWarning" xml:space="preserve">
+    <value>No file selected</value>
+  </data>
+  <data name="Main_Ok" xml:space="preserve">
+    <value>OK</value>
+  </data>
+  <data name="Main_OpenFolderNoteWarning" xml:space="preserve">
+    <value>Please select a folder</value>
+  </data>
+  <data name="Main_Print" xml:space="preserve">
+    <value>Print</value>
+  </data>
+  <data name="Main_RemoveAll" xml:space="preserve">
+    <value>Remove All Files</value>
+  </data>
+  <data name="Main_Yes" xml:space="preserve">
+    <value>Yes</value>
+  </data>
+  <data name="Merge_MoveDown" xml:space="preserve">
+    <value>Move Down</value>
+  </data>
+  <data name="Merge_MoveUp" xml:space="preserve">
+    <value>Move Up</value>
+  </data>
+  <data name="Merge_TotalPage" xml:space="preserve">
+    <value>{0} file(s) in total</value>
+  </data>
+</root>

+ 234 - 0
Demo/Examples/Compdfkit.Controls/Strings/Compress.zh.resx

@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="CompressInterruptWarning" xml:space="preserve">
+    <value>确定要中断压缩吗?</value>
+  </data>
+  <data name="CompressStr" xml:space="preserve">
+    <value>压缩</value>
+  </data>
+  <data name="Compress_Custom" xml:space="preserve">
+    <value>自定义</value>
+  </data>
+  <data name="Compress_High" xml:space="preserve">
+    <value>高</value>
+  </data>
+  <data name="Compress_Low" xml:space="preserve">
+    <value>低</value>
+  </data>
+  <data name="Compress_Medium" xml:space="preserve">
+    <value>标准</value>
+  </data>
+  <data name="Compress_NumberErrorWarning" xml:space="preserve">
+    <value>输入的文件大小错误,请重试</value>
+  </data>
+  <data name="Compress_OKWarning" xml:space="preserve">
+    <value>压缩文件成功!</value>
+  </data>
+  <data name="Compress_OptimizationQuality" xml:space="preserve">
+    <value>优化选项</value>
+  </data>
+  <data name="ContentSelection_CancelDo" xml:space="preserve">
+    <value>撤销</value>
+  </data>
+  <data name="ContentSelection_Exit" xml:space="preserve">
+    <value>退出</value>
+  </data>
+  <data name="ContentSelection_Output" xml:space="preserve">
+    <value>导出</value>
+  </data>
+  <data name="Convert_Progress" xml:space="preserve">
+    <value>进度</value>
+  </data>
+  <data name="Corp_Customize" xml:space="preserve">
+    <value>自定义裁剪区域</value>
+  </data>
+  <data name="Corp_Customize_PRM" xml:space="preserve">
+    <value>裁剪后的页面无法恢复到原始状态,是否继续裁剪?</value>
+  </data>
+  <data name="FileInfo_Location" xml:space="preserve">
+    <value>位置</value>
+  </data>
+  <data name="FileInfo_Size" xml:space="preserve">
+    <value>大小</value>
+  </data>
+  <data name="Main_AddFile" xml:space="preserve">
+    <value>添加文档</value>
+  </data>
+  <data name="Main_Cancel" xml:space="preserve">
+    <value>取消</value>
+  </data>
+  <data name="Main_CompletedState" xml:space="preserve">
+    <value>完成</value>
+  </data>
+  <data name="Main_Copy" xml:space="preserve">
+    <value>复制</value>
+  </data>
+  <data name="Main_Crop" xml:space="preserve">
+    <value>裁剪</value>
+  </data>
+  <data name="Main_Delete" xml:space="preserve">
+    <value>删除</value>
+  </data>
+  <data name="Main_FailedState" xml:space="preserve">
+    <value>失败</value>
+  </data>
+  <data name="Main_FileName" xml:space="preserve">
+    <value>文件名</value>
+  </data>
+  <data name="Main_HintWarningTitle" xml:space="preserve">
+    <value>提示</value>
+  </data>
+  <data name="Main_Interrupt" xml:space="preserve">
+    <value>中断</value>
+  </data>
+  <data name="Main_MenuHelp_About" xml:space="preserve">
+    <value>关于</value>
+  </data>
+  <data name="Main_No" xml:space="preserve">
+    <value>否</value>
+  </data>
+  <data name="Main_NoSelectedFilesWarning" xml:space="preserve">
+    <value>没有选择文件</value>
+  </data>
+  <data name="Main_Ok" xml:space="preserve">
+    <value>确认</value>
+  </data>
+  <data name="Main_OpenFolderNoteWarning" xml:space="preserve">
+    <value>请选择文件夹</value>
+  </data>
+  <data name="Main_Print" xml:space="preserve">
+    <value>打印</value>
+  </data>
+  <data name="Main_RemoveAll" xml:space="preserve">
+    <value>移除全部文件</value>
+  </data>
+  <data name="Main_Yes" xml:space="preserve">
+    <value>是</value>
+  </data>
+  <data name="Merge_MoveDown" xml:space="preserve">
+    <value>下移</value>
+  </data>
+  <data name="Merge_MoveUp" xml:space="preserve">
+    <value>上移</value>
+  </data>
+  <data name="Merge_TotalPage" xml:space="preserve">
+    <value>共{0}个文件</value>
+  </data>
+</root>

+ 2 - 0
Demo/Examples/Compdfkit.Controls/packages.config

@@ -2,4 +2,6 @@
 <packages>
   <package id="Nager.Country" version="4.0.0" targetFramework="net461" />
   <package id="PresentationFramework.Aero2" version="1.0.1" targetFramework="net461" />
+  <package id="WindowsAPICodePack-Core" version="1.1.1" targetFramework="net462" />
+  <package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net462" />
 </packages>