程序员的知识教程库

网站首页 > 教程分享 正文

C# Winform Aot发布DataGridView复制问题

henian88 2025-05-03 14:12:31 教程分享 5 ℃ 0 评论

这几天使用winform开发一个小工具,用了datagridview,但是发现当时使用复制时候,会弹出报错。

经过分析,理解 Clipboard并没办法 COM,没办法。

首先想到办法,那就是拦截 复制功能,正常来说,操作都是 按Ctrl +C。

那就直接拦截 按键操作,可是当用户处于编辑状态情况,不能拦截,需要还是正常操作。

首先需要操作剪切板,又不能使用Clipboard ,那唯一办法就是自己写api调用。分析官方文档。然后使用.NET调用

完整代码如下

internal class WindowsClipboard
{
    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool OpenClipboard(IntPtr hWndNewOwner);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool CloseClipboard();

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool EmptyClipboard();

    [DllImport("kernel32.dll")]
    private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);

    [DllImport("kernel32.dll")]
    private static extern IntPtr GlobalLock(IntPtr hMem);

    [DllImport("kernel32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GlobalUnlock(IntPtr hMem);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);

    private const uint CF_UNICODETEXT = 13;
    private const uint GMEM_MOVEABLE = 0x0002;
    private const uint GMEM_ZEROINIT = 0x0040;

    public static void SetText(string text)
    {
        if (!OpenClipboard(IntPtr.Zero))
        {
            throw new Exception(#34;打开剪贴板失败 (错误代码: {Marshal.GetLastWin32Error()})");
        }

        try
        {
            EmptyClipboard();

            // 计算字节长度(包含终止空字符)
            var bufferSize = (text.Length + 1) * 2;
            var hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (UIntPtr)bufferSize);

            if (hGlobal == IntPtr.Zero)
            {
                throw new Exception("内存分配失败");
            }

            try
            {
                var pGlobal = GlobalLock(hGlobal);

                if (pGlobal == IntPtr.Zero)
                {
                    throw new Exception("内存锁定失败");
                }

                try
                {
                    // 将字符串复制到非托管内存
                    var bytes = Encoding.Unicode.GetBytes(text);
                    Marshal.Copy(bytes, 0, pGlobal, bytes.Length);
                }
                finally
                {
                    GlobalUnlock(hGlobal);
                }

                if (SetClipboardData(CF_UNICODETEXT, hGlobal) == IntPtr.Zero)
                {
                    throw new Exception(#34;设置剪贴板数据失败 (错误代码: {Marshal.GetLastWin32Error()})");
                }

                // 成功设置后,hGlobal 所有权已转移给剪贴板
                hGlobal = IntPtr.Zero;
            }
            finally
            {
                if (hGlobal != IntPtr.Zero)
                {
                    GlobalFree(hGlobal);
                }
            }
        }
        finally
        {
            CloseClipboard();
        }
    }

    [DllImport("kernel32.dll")]
    private static extern IntPtr GlobalFree(IntPtr hMem);
}

使用时候即

WindowsClipboard.SetText(clipboardText);

经过测试,aot发布后可以使用

处理DataGridView中的拦截和数据

    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.C && e.Control)
        {
            if (!this.IsCurrentCellInEditMode)
            {
                this.EndEdit();
                if (this.SelectedCells.Count == 0)
                    return;
                // 获取所有选中的单元格并按行列排序
                var clipboardText = string.Join(Environment.NewLine,
                    this.SelectedCells.Cast<DataGridViewCell>()
                    .GroupBy(c => c.RowIndex)// 按行分组
                    .OrderBy(g => g.Key)// 按行号排序
                    .Select(g => string.Join("\t", 
                    g.OrderBy(c => c.ColumnIndex)
                    .Select(c => c.FormattedValue?.ToString() ?? "")))); // 使用格式化后的值

                WindowsClipboard.SetText(clipboardText);
                return;
            }
        }
        base.OnKeyDown(e);
    }

保存发布后完全没问题

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表