.NET6 WPF 实现截图功能以及快捷键截图

该代码示例展示了如何在C#中实现屏幕截图功能,包括隐藏主窗体、截取屏幕、显示截图窗口以及处理截图后的编辑操作。此外,还利用WindowsAPI注册全局快捷键Ctrl+Alt+A,以便在应用程序后台时也能触发截图。用户在截图窗口中可以选取特定区域并进行确认或取消操作。
摘要由CSDN通过智能技术生成

1.需要添加引用

        System.Drawing.Common

2.主界面中添加一个按钮用于出发截图,按钮事件如下:

【MainWindow.xaml.cs】

        //截图按钮
        private void BTCut_Click(object sender, RoutedEventArgs e)
        {
            //截图时隐藏主窗体
            this.Hide();
            //截取屏幕的一帧,并打开一个窗体显示出来
            ScreenWindow snapWin = new ScreenWindow(CaptureCurrentScreen())
            {
                //ScreenWindow处理完成后回调的处理事件
                sendMessage = GetImageHandler
            };

            snapWin.ShowDialog();
        }

        private void GetImageHandler(Bitmap bitmap) 
        {
            //此处写处理截图的逻辑
        }

        /// <summary>
        /// 截取屏幕
        /// </summary>
        /// <returns></returns>
        public static Bitmap CaptureCurrentScreen()
        {
            //创建与屏幕大小相同的位图对象
            var bmpScreen = new Bitmap((int)ScreenUtils.GetScreenWidth(), (int)ScreenUtils.GetScreenHeight(), System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            //使用位图对象来创建Graphics的对象
            using (Graphics g = Graphics.FromImage(bmpScreen))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;   //设置平滑模式,抗锯齿
                g.CompositingQuality = CompositingQuality.HighQuality;  //设置合成质量
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;     //设置插值模式
                g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;   //设置文本呈现的质量
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;    //设置呈现期间,像素偏移的方式

                //利用CopyFromScreen将当前屏幕截图并将内容存储在bmpScreen的位图中
                g.CopyFromScreen(0, 0, 0, 0, bmpScreen.Size, CopyPixelOperation.SourceCopy);
            }

            return bmpScreen;
        }

3.截屏后显示的窗体ScreenWindow代码如下

前台样式:

<Window x:Class="myTestApp.Views.ScreenWindow"
        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:myTestApp.Views"
        mc:Ignorable="d"
        WindowState="Maximized" WindowStyle="None" AllowsTransparency="True" Background="Transparent"
        Title="ScreenWindow" Height="450" Width="800">
    <Grid>
        <InkCanvas Margin="0,0,0,0" Name="Ink" Visibility="Visible" EditingModeInverted="Select" EditingMode="Select" Cursor="Cross" MouseDown="Ink_MouseDown" MouseMove="Ink_MouseMove" MouseUp="Ink_MouseUp" MouseRightButtonDown="Ink_MouseRightButtonDown">
        </InkCanvas>
        <Border Name="Bord" Visibility="Collapsed" BorderThickness="2" HorizontalAlignment="Left"   VerticalAlignment="Top" Cursor="Cross" BorderBrush="#FF09646D"/>
        <Button Name="Cancel" Visibility="Collapsed" Content="✘" FontSize="16" HorizontalAlignment="Left" Height="40" Margin="527,347,0,0" VerticalAlignment="Top" Width="40" BorderBrush="Red" Background="Red" Foreground="White" Click="Cancel_Click"/>
        <Button Name="Conf" Visibility="Collapsed" Content="✔" FontSize="16" HorizontalAlignment="Left" Height="40" Margin="527,347,0,0" VerticalAlignment="Top" Width="40" BorderBrush="#FF32510C" Background="#66C4EF3C" Foreground="White" Click="Conf_Click"/>
    </Grid>
</Window>

后台代码:

/// <summary>
    /// ScreenWindow.xaml 的交互逻辑
    /// </summary>
    public partial class ScreenWindow : Window
    {
        public delegate void SendMessage(Bitmap bitmap);
        public SendMessage sendMessage;
        #region Win32 API
        [DllImport("user32.dll")]
        static extern IntPtr GetDC(IntPtr ptr);
        [DllImport("gdi32.dll")]
        static extern int GetDeviceCaps(
        IntPtr hdc, // handle to DC
        int nIndex // index of capability
        );
        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
        #endregion
        #region DeviceCaps常量
        const int HORZRES = 8;
        const int VERTRES = 10;
        const int LOGPIXELSX = 88;
        const int LOGPIXELSY = 90;
        const int DESKTOPVERTRES = 117;
        const int DESKTOPHORZRES = 118;
        #endregion

        private bool IsSnap = false;

        private Bitmap ScreenShot;
        public ScreenWindow(Bitmap bitmap)
        {
            InitializeComponent();
            this.Topmost = true;
            ScreenShot = bitmap;
            MouseDown += Ink_MouseDown;
            MouseUp += Ink_MouseUp;
            MouseMove += Ink_MouseMove;
            MouseRightButtonDown += Ink_MouseRightButtonDown;
            BitmapSource source;
            IsSnap = true;

            try
            {
                source = Imaging.CreateBitmapSourceFromHBitmap(ScreenShot.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            }
            catch
            {
                source = null;
            }
            ImageBrush b = new ImageBrush();
            b.ImageSource = source;
            b.Stretch = Stretch.Fill;
            Ink.Background = b;
            Ink.EditingMode = InkCanvasEditingMode.None;
            this.WindowStartupLocation = WindowStartupLocation.Manual;
            this.Visibility = Visibility.Visible;
            this.Left = 0;
            this.Top = 0;
            this.Height = SystemParameters.VirtualScreenHeight;
            this.Width = SystemParameters.VirtualScreenWidth;
        }

        private bool ISDown = false;                    // 判断是否鼠标左键按下
        System.Windows.Point Startpoint = new System.Windows.Point();
        private void Ink_MouseDown(object sender, MouseButtonEventArgs e)
        {
            ISDown = true;
            Conf.Visibility = Visibility.Collapsed;
            Cancel.Visibility = Visibility.Collapsed;
            Startpoint = Mouse.GetPosition(this);
        }
        Rect rect;
        /// <summary>
        /// 根据鼠标移动画出矩形标识区域
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Ink_MouseMove(object sender, MouseEventArgs e)
        {
            if (IsSnap)
            {
                if (ISDown == true)
                {
                    System.Windows.Point point = Mouse.GetPosition(this);
                    rect = new Rect(Startpoint, point);
                    Bord.Visibility = Visibility.Visible;
                    Bord.Margin = new Thickness(rect.Left, rect.Top, 0, 0);
                    Bord.Height = rect.Height;
                    Bord.Width = rect.Width;
                }
            }
        }
        Rect snapArea = new Rect();
        private void Ink_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (IsSnap)
            {
                ISDown = false;
                if (Bord.Visibility == Visibility.Collapsed)
                {
                    Conf.Visibility = Visibility.Collapsed;
                    Cancel.Visibility = Visibility.Collapsed;
                }
                else
                {
                    Conf.Visibility = Visibility.Visible;
                    Cancel.Visibility = Visibility.Visible;
                }
                if (rect.Width >= 10 && rect.Height >= 10)
                {

                    if (System.Windows.Forms.SystemInformation.VirtualScreen.Height - rect.Bottom >= 0)
                    {
                        snapArea = rect;
                        Conf.Margin = new Thickness(rect.Right - 40, rect.Bottom, 0, 0);
                        Cancel.Margin = new Thickness(rect.Right - 80, rect.Bottom, 0, 0);

                    }
                    else
                    {
                        snapArea = rect;
                        Conf.Margin = new Thickness(rect.Left + 10, rect.Top + 22, 0, 0);
                        Cancel.Margin = new Thickness(rect.Left + 50, rect.Top + 22, 0, 0);
                    }
                }

            }

        }

        private void Ink_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            ISDown = false;
            Conf.Visibility = Visibility.Collapsed;
            Cancel.Visibility = Visibility.Collapsed;
            Bord.Visibility = Visibility.Collapsed;

        }

        private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape))
            {
                ISDown = false;
                Conf.Visibility = Visibility.Collapsed;
                Cancel.Visibility = Visibility.Collapsed;
                Bord.Visibility = Visibility.Collapsed;
                this.Close();
            }
        }
        /// <summary>
        /// 确认区域
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Conf_Click(object sender, RoutedEventArgs e)
        {
            if (IsSnap)
            {
                double dpi = getDpi();
                System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle((int)((snapArea.X + 2) * dpi), (int)((snapArea.Y + 2) * dpi), (int)((snapArea.Width - 4) * dpi), (int)((snapArea.Height - 4) * dpi));
                var bitmap1 = new Bitmap((int)(snapArea.Width * dpi), (int)(snapArea.Height * dpi), System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                using (Graphics g = Graphics.FromImage(bitmap1))
                {
                    g.CopyFromScreen(rectangle.X, rectangle.Y, 0, 0, rectangle.Size, CopyPixelOperation.SourceCopy);
                }
                this.Cursor = Cursors.Wait;
                sendMessage(bitmap1);

                this.Close();
            }


        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            sendMessage(null);
            this.Close();
        }

        /// <summary>
        /// 获取系统dpi,这一步很重要
        /// </summary>
        /// <returns></returns>
        double getDpi()
        {
            double dDpi = 1;
            IntPtr desktopDc = GetDC(IntPtr.Zero);
            float horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX);
            float verticalDPI = GetDeviceCaps(desktopDc, LOGPIXELSY);
            int dpi = (int)(horizontalDPI + verticalDPI) / 2;
            dDpi = 1 + ((dpi - 96) / 24) * 0.25;
            if (dDpi < 1)
            {
                dDpi = 1;
            }
            ReleaseDC(IntPtr.Zero, desktopDc);
            return dDpi;
        }
    }

4.附:ScreenUtils.cs


    public class ScreenUtils
    {
        /// <summary>
        /// 获取DPI百分比
        /// </summary>
        /// <param name="window"></param>
        /// <returns></returns>
        public static double GetDpiRatio(Window window)
        {
            var currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(window).Handle);
            return currentGraphics.DpiX / 96;
        }

        public static double GetDpiRatio()
        {
            return GetDpiRatio(Application.Current.MainWindow);
        }

        public static double GetScreenHeight()
        {
            return SystemParameters.PrimaryScreenHeight * GetDpiRatio();
        }

        public static double GetScreenActualHeight()
        {
            return SystemParameters.PrimaryScreenHeight;
        }

        public static double GetScreenWidth()
        {
            return SystemParameters.PrimaryScreenWidth * GetDpiRatio();
        }

        public static double GetScreenActualWidth()
        {
            return SystemParameters.PrimaryScreenWidth;
        }
    }

以上是实现截图功能的核心代码,接下来添加快捷键截图功能,通过Ctrl+Alt+A快捷截图

5.引用WindowsApi,用于注册全局快捷键,这样即使主窗体不在前台显示也能使用快捷键截图

添加HotKey.cs

    public class HotKey
    {

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool RegisterHotKey(
                IntPtr hWnd, // handle to window   
                int id, // hot key identifier   
                KeyModifiers fsModifiers, // key-modifier options   
                System.Windows.Forms.Keys vk // virtual-key code   
        );

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool UnregisterHotKey(
            IntPtr hWnd, // handle to window   
            int id // hot key identifier   
        );
        [Flags]
        public enum KeyModifiers
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            Windows = 8
        }
    }

6.在主窗体完成初始化时注册全局快捷键

【MainWindow.xaml.cs】


        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            this.myHandle = new WindowInteropHelper(this).Handle;
            //组合键
            ctrHotKey = (uint)(KeyModifiers.Alt | KeyModifiers.Control);
            //注册
            bool f = RegisterHotKey(this.myHandle, 100, (KeyModifiers)ctrHotKey, Keys.A);//这时热键为Alt+CTRL+A
            HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
            source.AddHook(WndProc);
        }
        //快捷键响应事件
        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handle)
        {
            //Debug.WriteLine("hwnd:{0},msg:{1},wParam:{2},lParam{3}:,handle:{4}"
            //                ,hwnd,msg,wParam,lParam,handle);
            string sid = wParam.ToString();
            switch (sid)
            {
                case "100":
                    BTCut_Click(null, null);
                    break;
                default:
                    break;
            }
            return IntPtr.Zero;
        }

7.窗体程序退出时要注销掉全局快捷键

【MainWindow.xaml.cs】


private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            UnregisterHotKey(this.myHandle, 100);//卸载快捷键
        }

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
In .NET 6 and later versions, the `System.Windows.Forms` namespace is not included in the default installation of WPF applications. However, you can still use the `FolderBrowserDialog` class in your WPF application by adding a reference to the `System.Windows.Forms` NuGet package and using the `System.Windows.Forms.Integration` namespace. Here are the steps to use `FolderBrowserDialog` in .NET 6 WPF: 1. Add a reference to the `System.Windows.Forms` NuGet package in your WPF project. 2. Add the following using statements to the top of your code file: ```csharp using System.Windows.Forms; using System.Windows.Forms.Integration; ``` 3. In your code, create a `FolderBrowserDialog` object and use the `ShowDialog` method to display the dialog box: ```csharp FolderBrowserDialog dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { // do something with the selected folder } ``` 4. If you want to use the `FolderBrowserDialog` in a WPF window or page, you can use the `WindowsFormsHost` control to host the dialog box: ```xml <Window xmlns:winforms="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration" xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms" ...> <Grid> <winforms:WindowsFormsHost> <forms:FolderBrowserDialog x:Name="folderDialog" /> </winforms:WindowsFormsHost> </Grid> </Window> ``` Then, you can use the `ShowDialog` method to display the dialog box: ```csharp if (folderDialog.ShowDialog() == DialogResult.OK) { // do something with the selected folder } ``` Note that you will also need to add a reference to the `WindowsFormsIntegration` assembly in your WPF project.
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值