DotNet · 2022年5月26日

直接复制DataGridView中的数据,中文会变成乱码

我自已的解决方案:
响应KeyPress事件,在KeyPress事件中执行剪贴板内容的自定义
   
 Private Sub DataGridViewX1_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles DataGridViewX1.KeyPress
        If (AscW(e.KeyChar.ToString()) = 3 AndAlso DataGridViewX1.RowCount > 0) Then
            Dim pDataObject As DataObject = DataGridViewX1.GetClipboardContent()
            If (pDataObject Is Nothing) Then
                Return
            End If
            Dim pContent As String = pDataObject.GetData(DataFormats.UnicodeText).ToString()
            Try
                Clipboard.Clear()
                Clipboard.SetText(pContent, TextDataFormat.UnicodeText)
            Catch ex As Exception
                MsgBox(ex.Message, MsgBoxStyle.OkOnly, My.Application.Info.Title)
            End Try
        End If
    End Sub

以下是其他解决方案,部份选材自网上,解决方案2是在其他项目中使用的解决方案

解决方案1是:手工选择Unicode Text格式方式进行粘贴

解决方案2是:使用Excel对像,逐格导出数据。

解决方案3是:使用VB代码来进行自动复制粘贴,在粘贴时选择Unicode 文本方式

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click


        Try
            Dim filepath As String = Application.StartupPath & "/" & Now.ToFileTimeUtc & ".xls"
            Dim objexcel As New Excel.Application()
            Dim objbook As Excel.Workbook = objexcel.Workbooks.Add()
            objbook.SaveAs(filepath)

            '设置复制模式为:连同行头和表头一起复制
            Me.DataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText
            '如果不需要复制行头,就把它隐藏掉
            Me.DataGridView1.RowHeadersVisible = False
            '选中DataGridView1的所有内容
            Me.DataGridView1.SelectAll()
            '判断DataGridView1中是否有选中单元格(与上面好像有点矛盾,自行处理)
            If Me.DataGridView1.GetCellCount(DataGridViewElementStates.Selected) > 0 Then
                Clipboard.SetDataObject(Me.DataGridView1.GetClipboardContent())
            End If
             '直接在Excel中粘贴
            'objexcel.ActiveSheet.paste()
            '為防止亂碼。使用選擇性粘貼
            '下面這一行,相當于在Excel中點擊右鍵->選擇性粘貼->文本
            'objexcel.ActiveSheet.PasteSpecial(Format:="文本", Link:=False, DisplayAsIcon:=False)

            '修改为选择性粘贴--> Unicode 文本

             objexcel.ActiveSheet.PasteSpecial(Format:="Unicode 文本", Link:=False, DisplayAsIcon:=False)
            '选中Excel所有单元格
            objexcel.Cells.Select()
            '不自动换行
            objexcel.Selection.WrapText = False
            '自动调整列宽
            objexcel.Columns.AutoFit()
            '储存
            objbook.Save()
            '退出
            objbook.Close()
            objexcel.Quit()
            objbook = Nothing
            objexcel = Nothing
            killexcel()
            '提示打开文件
            If MessageBox.Show("档案储存在:" & filepath & ",你要打开吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) = Windows.Forms.DialogResult.Yes Then
                Process.Start(filepath)
            End If
        Catch ex As Exception
            killexcel()
            MsgBox(ex.Message)
        End Try
    End Sub

    '杀掉程序创建的Excel进程
    Private Sub killexcel()
        Try
            For Each proc As Process In Process.GetProcessesByName("EXCEL")
                If proc IsNot Nothing AndAlso proc.MainWindowTitle = "" Then
                    proc.Kill()
                End If
            Next
        Catch ex As Exception
            Throw ex
        End Try
    End Sub

解决方案4:在DatagridView端想办法,让复制的格式本身就是文本格式,这样在粘贴的时候,就无需转化成文本格式了

参考:

最近,用datagridview,发现他已经自带ctrl+C复制功能了,但复制到Excel时出现乱码,必须用选择性粘贴。感觉比较麻烦,所以添加keyup事件来改写ctrl+C功能。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        private void ctrlC_KeyUp(object sender, KeyEventArgs e)
        {            
            //System.Diagnostics.Debug.Print((e.KeyCode==Keys.C).ToString());
            //System.Diagnostics.Debug.Print((e.Control).ToString());
            if (e.KeyCode == Keys.C && e.Control) 
            {
                if (sender != null && sender.GetType() == typeof(DataGridView))
                {
                    DataGridView dgv = (DataGridView)sender;
                    dgv.RowHeadersVisible = false;
                    Clipboard.SetText(dgv.GetClipboardContent().GetData(DataFormats.UnicodeText, true).ToString());
                    dgv.RowHeadersVisible = true;
                }
            }
        }

正常复制下已经没有问题了,但出现一个很怪的问题,当我ctrl C按得很快的时候(准确的说是先释放ctrl键的时候),发现仍然出现乱码,我知道先释放ctrl键应该是进不了我的if里,但为什么自带的ctrl C能正常进行复制呢?难道自带的ctrl C是写在keydown里的?于是,我做了两个实验验证一下:
1、不添加我自己的keyup事件下,用自带ctrl C进行复制,先释放ctrl键,结果是可以复制。(似乎证明自带ctrl C功能,在keydown事件里)
2、不添加我自己的keyup事件下,选择部分cell按ctrl C,不释放,再选择别一组cell,再释放ctrl C,结果是两组cell全部被复制。(似乎证明自带ctrl 功能,在keyup事件里)
    这两种情况,出现了不一样的结论,于是我怀疑是不是自带ctrl C功能,把keydown keyup事件都写进了方法。我又试着把上面自己写的ctrl C方法,同时添加给keydown 和keyup,但发现先释放ctrl键的时候仍然是乱码。
    也许datagridview自带的功能优先权更高,这我就不太清楚了,但我想知道有没有办法能把自带的ctrl C方法给屏蔽掉。或继承重写这个功能?因为有时按快了ctrl C经常容易出现ctrl先释放的问题,这样就又出现乱码了。

—————————————

System.Windows.Forms.DataGridView控件以数据网络的方法呈现数据,可以非常方便的用它绑定数据源,不需要编辑多少代码就可以实现对数据源的增删改功能。偶然发现它有一个小小的问题,我们用快捷键复制(Ctrl+C/Ctrl+Insert)表格内容后,到常用的办公处理软件(如微软Office系列和Sun的OpenOffice)中粘贴,那么带有Unicode字符的内容会显示会乱码。使用反射工具查看了DataGridView控件对此功能的实现方法,是由于它直接采用了剪贴版类的SetDataObject方法而没有指定其格式,那么它的格式似乎被认为是ANSI的HTML格式+Unicode内容,所以直接粘贴到字处理软件或者表格处理软件(有时,微软Excel会因此无响应)显示出汉字等Unicode字符却成了乱码。 

Clipboard.SetDataObject(clipboardContent); 

此种情况可以利用“选择性粘贴”将其格式按“无格式文本”粘贴就可以了。 

总不要是这样子,我们还可以编写一个DataGridView子类,重写ProcessDataGridViewKey方法,当它在处理“复制”的快捷键时用我们重新实现的ProcessInsertKey来完成任务,将复制剪贴板功能改为Unicode格式的SetText方法即可。代码如下(修改的剪贴板功能在29行): 

public class MyDataGridView : DataGridView    
{    
     [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]    
    protected override bool ProcessDataGridViewKey(KeyEventArgs e)    
     {    
        switch (e.KeyCode)    
         {    
            case Keys.Insert:    
            case Keys.C:    
                return this.ProcessInsertKey(e.KeyData);    
            default:    
                break;    
         }    
        return base.ProcessDataGridViewKey(e);    
     }    
   
     [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]    
    protected new bool ProcessInsertKey(Keys keyData)    
     {    
        if ((((keyData & (Keys.Alt | Keys.Control | Keys.Shift)) == Keys.Control) ||    
             (((keyData & (Keys.Alt | Keys.Control | Keys.Shift)) == (Keys.Control | Keys.Shift))    
             && ((keyData & Keys.KeyCode) == Keys.C)))    
             && (this.ClipboardCopyMode != DataGridViewClipboardCopyMode.Disable))    
         {    
             DataObject clipboardContent = this.GetClipboardContent();    
            if (clipboardContent != null)    
             {    
                //Clipboard.SetDataObject(clipboardContent);    
                 Clipboard.SetText(clipboardContent.GetData(DataFormats.UnicodeText).ToString());    
                return true;    
             }    
         }    
        return false;    
     }    
}  


最新电影,电视剧,尽在午夜剧场

电影电视剧午夜不寂寞