Membuat Background Datagridview seperti Row

Hallo, sudah lama saya tidak muncul di dunia blog. Pada kesempatan kali ini saya mau berbagi tips bahasa pemrograman C#, point-nya pada Datagridview. Pada umumnya tampilan datagridview pada saat terisi data dari database yang jumlah record-nya kurang dari tinggi datagridview ,maka akan terlihat ‘bolong’ di bawahnya. Untuk lebih jelasnya lihat gambar di bawah ini :

DataGridView_sebelum

DataGridView_sebelum

Bisa kita lihat gambar di atas terlihat kosong di bagian bawah, hal itu membuat datagridview kurang menarik.  Jika masalah diatas merupakan masalah anda, maka saya punya solusinya, berikut kodenya:

private void newDataGridView1_Paint(object sender, PaintEventArgs e)
{
 List<int> displayedIndex = new List<int>();
 for (int i = 0; i < ((DataSet)newDataGridview1.DataSource).Tables[0].Columns.Count; i++)
 {
    if (newDataGridView1.Columns[i].Visible == true)
    {
      displayedIndex.Add(i);
    }
 }

 int fIndex = displayedIndex[0];//mengetahui index dari visible column
 Rectangle rc = new Rectangle(newDataGridView1.GetCellDisplayRectangle(fIndex, newDataGridView1.Rows.Count - 1, true).X, newDataGridView1.GetCellDisplayRectangle(3, newDataGridView1.Rows.Count - 1, true).Y + 22, newDataGridView1.Width, (newDataGridView1.Height - (newDataGridView1.Rows.Count * 22)));

 #region "editable"
 rc.Inflate(1, 1);
 rc.Width = rc.Width - 4;
 #endregion

 e.Graphics.FillRectangle(new SolidBrush(newDataGridView1.DefaultCellStyle.BackColor), rc);
 Pen pen = new Pen(Color.FromArgb(208, 215, 229), 0.2f);
 int jmlKurang = (newDataGridView1.Height + newDataGridView1.ColumnHeadersHeight - (newDataGridView1.Rows.Count * newDataGridView1.Rows[0].Height)) / 22;
 for (int j = 0; j < jmlKurang; j++)
 {
   switch (newDataGridView1.AdvancedCellBorderStyle.Bottom)
   {
    case DataGridViewAdvancedCellBorderStyle.None:
    break;
    case DataGridViewAdvancedCellBorderStyle.Single:
    e.Graphics.DrawLine(pen, rc.X, rc.Y, rc.X + rc.Width - 1, rc.Y);
      for (int a = 0; a < displayedIndex.Count -1; a++)
      {
        float vLX = newDataGridView1.GetCellDisplayRectangle(displayedIndex[a] + 1, newDataGridView1.Rows.Count - 1, true).X;
        e.Graphics.DrawLine(pen, vLX, rc.Y, vLX, rc.Y + 22);
      }    
    break;
    case DataGridViewAdvancedCellBorderStyle.Inset:
    case DataGridViewAdvancedCellBorderStyle.InsetDouble:
    case DataGridViewAdvancedCellBorderStyle.Outset:
    case DataGridViewAdvancedCellBorderStyle.OutsetDouble:
    case DataGridViewAdvancedCellBorderStyle.OutsetPartial:
    break;
   }
 rc.Y += 22;
 }
}

Script diatas diletakkan pada event Paint dari ‘newDatagridView1’. Copy Paste aja script diatas. Mungkin kode diatas kurang sempurna bagi anda2 yang sudah profesional, untuk itu andalah yang menyempurnakan, hehehehe :D. Untuk script block “editable”, anda bisa mengedit ukuran dari rectangle, tergantung dari style datagridview anda. Kemudian pada baris kode “DataGridViewAdvancedCellBorderStyle”,  saya hanya membuat dengan style Single. Untuk style lainnya sekali lagi anda yang menyempurnakan :D.  Oh ya, kode diatas terdapat angka 22. Angka tersebut merupakan tinggi default dari sebuah row, anda bisa mengubah sesuai tinggi dari row anda. Perlu di ingat, set ‘False’ untuk property AllowUserToResizeRows, agar tinggi row tidak berubah-ubah. Untuk kode diatas tampilan akan seperti berikut:

DataGridView_sesudah

DataGridView_sesudah

Gimana? Lumayan kan buat bagusin tampilan. Oke, sekian dari saya dan terima kasih :D. Moga bermanfaat.

Group By Data di C# dengan LINQ

Saya masih berbicara tentang bahasa pemrograman C#. Di SQL-Server kita tahu kalau tidak ada pengelompokan data berdasarkan field tertentu atau bisa disebut dengan “GROUP BY” dalam MySQL. Untuk itu ada tips khusus untuk modifikasi script bagi anda dengan menggunakan LINQ.
Karena Linq merupakan Class bawaan dari .NET, yang memungkinkan anda untuk mengelola data secara langsung. Berikut ini adalah contoh kode, kita asumsikan kita menggunakan tabel ‘pegawai_tabel’ yang di group dengan field ‘kota_asal’

var query = from row in pegawai_tabel
 group row by row.Field<string>("kota_asal");

Dari kode diatas bisa diartikan bahwa var query  menjadi enum dari baris(row) tabel yang sudah di kelompokkan (IQueryable <IGrouping <string, pegawai_tabel>>). Setiap item pencacahan ini akan men-define sebuah group (IGrouping <string, pegawai_tabel>). Untuk tabel dan field yang saya gunakan adalah ‘pegawai_tabel’ yang dikelompokkan berdasarkan ‘kota_asal’. Anda bisa mengganti sesuai tabel dan field yang anda inginkan tentunya sesuai dengan database anda.

Seperti yang bisa kita lihat dalam kode diatas, IGrouping hanya menambahkan beberapa hal:

– key, merupakan kunci dari group(“kota_asal” dalam contoh yg saya buat).
– item yang dikelompokkan oleh key. Untuk mengambil item ini, anda harus menelusuri kelompok yang merupakan pencacahan dari group itu sendiri dengan menggunakan metode perulangan seperti contoh di bawah ini:

foreach (var a in query)
{
    var peg = a.Key; //merupakan key dari group 
    foreach (var pg in a)
        System.Console.WriteLine(pg.kota_asal);
}

Kode diatas akan menampilkan kota_asal dari pegawai2 yang sudah di group berdasarkan kota_asal.
Sekian dari saya, moga2 bermanfaat.
Ingat : Group By beda dengan Order By !

Raw Printer di C#

Bagi anda yang mengerjakan aplikasi atau program yang berhubungan dengan kasir penjualan pasti akan mendapatkan kasus “Bagaimana cara mencetak struk”. Disini anda mungkin menggunakan layanan print dari  Crystal Report dan Report Viewer bawaan dari Windows.

Salah satu kelemahan dari layanan ini adalah file akan tercetak sebagai graphic/gambar bukan sebagai dot per inch. Jadi apabila program yang Anda kerjakan harus mencetak struk dengan jumlah baris-baris data yang dicetak tidak dapat diprediksi jumlahnya dan ukuran kertas bertipe ROLL, maka menggunakan layanan dari Crystal Report dan Report Viewer ini bukan suatu solusi yang tepat. Belum lagi masalah jenis printer, bila kita mencetak graphic untuk struk di printer jenis Dot Matrix, proses cetak akan memakan waktu yang cukup lama.

Kita akan mencoba untuk membuat program dengan mencetak ke printer tipe Dot Matrix dengan cara di bawah ini :

1. Buat Class tersendiri untuk mengirim RAW data ke Printer Dot Matrix

    using System;
    using System.Runtime.InteropServices;
    using System.IO;
    public class RawPrinterHelper
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public class DOCINFOA
        {
            [MarshalAs(UnmanagedType.LPStr)]
            public string pDocName;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pOutputFile;
            [MarshalAs(UnmanagedType.LPStr)]
            public string pDataType;
        }

        [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

        [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

        [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndDocPrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool StartPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool EndPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
       public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
        {
            Int32 dwError = 0, dwWritten = 0;
            IntPtr hPrinter = new IntPtr(0);
            DOCINFOA di = new DOCINFOA();
            bool bSuccess = false; // Asumsikan proses printer gagal

            di.pDocName = "My C#.NET RAW Document";
            di.pDataType = "RAW";

            //Buka printer.
            if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
            {
               //Memulai dokumen printer
                if (StartDocPrinter(hPrinter, 1, di))
                {
                    // Memulai halaman dokumen.
                    if (StartPagePrinter(hPrinter))
                    {
                        // Meng-convert string dalam bentuk Byte
                        bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                        EndPagePrinter(hPrinter);
                    }
                    EndDocPrinter(hPrinter);
                }
                ClosePrinter(hPrinter);
            }
            // Jika Anda tidak berhasil, GetLastError dapat memberikan informasi lebih lanjut
            if (bSuccess == false)
            {
                dwError = Marshal.GetLastWin32Error();
            }
            return bSuccess;
        }

        public static bool SendStringToPrinter(string szPrinterName, string szString)
        {
            IntPtr pBytes;
            Int32 dwCount;
            //Berakarakter di dalam string?
            dwCount = szString.Length;
            //Ubah ke tipe text ANSI
            pBytes = Marshal.StringToCoTaskMemAnsi(szString);
            // Kirim text ANSI ke Printer
            SendBytesToPrinter(szPrinterName, pBytes, dwCount);
            Marshal.FreeCoTaskMem(pBytes);
            return true;
        }

        //Untuk  cetak file (*.txt) ke printer
       public static bool SendFileToPrinter(string szPrinterName, string szFileName)
        {
            // Buka File
            FileStream fs = new FileStream(szFileName, FileMode.Open);
            // Buat BinaryReader di file.
            BinaryReader br = new BinaryReader(fs);
            // dekalarasikan array untuk menampung isi file.
            Byte[] bytes = new Byte[fs.Length];
            bool bSuccess = false;
            IntPtr pUnmanagedBytes = new IntPtr(0);
            int nLength;

            nLength = Convert.ToInt32(fs.Length);
            // Membaca isi file ke dalam Array.
            bytes = br.ReadBytes(nLength);
            // Mengalokasikan beberapa memori ke bytes tersebut
            pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
            // Copy array byte yang sudah di proses ke pUnmanagedBytes
            Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
            // Kirim bytes ke printer.
            bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
            // Hapus semua memory yang sudah di pakai.
            Marshal.FreeCoTaskMem(pUnmanagedBytes);
            return bSuccess;
        }
    }

2. Cara Menggunakan Fungsi2 di atas

*Mengirim String langsung ke printer
    private void btnPrint_Click(object sender, EventArgs e)
    {
       string s = "Hello\n";
       s += "World";
       PrintDialog printDialog1 = new PrintDialog();
       if (DialogResult.OK == printDialog1.ShowDialog(this))
       {
          RawPrinterHelper.SendStringToPrinter(printDialog1.PrinterSettings.PrinterName, s);
       }
    }

 *Mengirim file ke printer
    private void btnPrint_Click(object sender, EventArgs e)
    {
       PrintDialog printDialog1 = new PrintDialog();
       if (DialogResult.OK == printDialog1.ShowDialog(this))
       {
          RawPrinterHelper.SendFileToPrinter(printDialog1.PrinterSettings.PrinterName, "c:\\Test.txt");
       }
    }

semoga bermanfaat bagi yang membutuhkan 😉

public class RawPrinterHelper
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;

[DllImport(“winspool.Drv”, EntryPoint = “OpenPrinterA”, SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

[DllImport(“winspool.Drv”, EntryPoint = “ClosePrinter”, SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);

[DllImport(“winspool.Drv”, EntryPoint = “StartDocPrinterA”, SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

[DllImport(“winspool.Drv”, EntryPoint = “EndDocPrinter”, SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);

[DllImport(“winspool.Drv”, EntryPoint = “StartPagePrinter”, SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);

[DllImport(“winspool.Drv”, EntryPoint = “EndPagePrinter”, SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);

[DllImport(“winspool.Drv”, EntryPoint = “WritePrinter”, SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

Menggabungkan kolom header DataGridView C#

Sama dengan postingan saya sebelumnya yaitu tentang DataGridView. Kali ini saya ingin berbagi tips cara untuk menggabungkan beberapa Header kolom dari datagridview menjadi hanya satu kolom header. Sebenarnya bukan penggabungan atau merge tapi lebih tepatnya menutupi beberapa kolom header yang kita inginkan dengan kolom header buatan kita sendiri.

Inilah gambar sebelum penggabungan kolom header:

Kolom sebelum

Kolom sebelum

Langsung saja ini kodenya dalam C#, ini adalah method untuk mengambil rectangle kolm yg nantinya akan di tempel pada header kolom yang ingin digabung.

#region method
private Rectangle getRectColumnHeader(DataGridView dgv, int startCol, int endCol)
 {
 Rectangle rc = this.newDataGridView1.GetCellDisplayRectangle(startCol,-1, true);
 int newColWidth = 0;
 for(int i=startCol;i<=endCol;i++)
 {
 newColWidth += newDataGridView1.Columns[i].Width;
 }
 rc.Width = newColWidth;

 return rc;
 }
#endregion

Oke, bagi yang belum tahu fungsi dari beberapa kode di atas, berikut ini penjelasannya:
-DataGridView dgv –> datagridview yang akan kita merge kolom header-nya.
-int startCol –> index dari awal kolom yang akan kita gabung.
-int endCol –> index dari akhir kolom yang kita gabung.
-GetCellDisplayRectangle –> untuk mengambil rectangle dari kolom header.
-newColWidth += newDataGridView1.Columns[i].Width –> menambahkan lebar dari kolom baru dengan lebar2 kolom yang akan di gabung.

Begitulah singkat penjelasan dari saya. Apabila masih kurang mengerti tolong googling bagaimana cara mengambil rectangle dari cell datagridview. Oke ?.. heheheh 😀

Implementasi method ditaruh pada event Paint di Datagridview anda:

private void newDataGridView1_Paint(object sender, PaintEventArgs e)
{
 Rectangle r1 = getRectColumnHeader(newDataGridView1, 1, 2);//memanggil methode getRectColumnHeade
 LinearGradientBrush arrowBrush = new LinearGradientBrush(r1, Color.FromArgb(245, 249, 251), Color.FromArgb(212, 220, 233), 90f);
 e.Graphics.FillRectangle(arrowBrush, r1);
 Font drawFont = new Font("Arial", 10, FontStyle.Bold);
 StringFormat format = new StringFormat();
 format.Alignment = StringAlignment.Center;
 format.LineAlignment = StringAlignment.Center;
 e.Graphics.DrawString("KOLOM GABUNGAN", drawFont,
      new SolidBrush(this.newDataGridView1.ColumnHeadersDefaultCellStyle.ForeColor),
      r1,
      format);
}

Penjelasan singkat:
-r1->mengambil rectangle dari kolom header dari kolom header index 1 sampai 2 ( edit sesuai selera).
-LinearGradientBrush arrowBrush–>membuat warna gradien dengan direction 90 derajat atau vertical.
-format–> merupakan format dari string yang akan kita tampilkan di Kolom gabungan. String bisa di ubah, contoh diatas “KOLOM GABUNGAN”.
-kode yang lainnya mohon di resapi sendiri dan di modifikasi sendiri. Script diatas hanya script dasar.. 😀

Jeng jeng jeng, inilah tampilan setelah di tambah kode diatas:

Kolom sesudah

Kolom sesudah

Gimana? bagus gak? datagridview saya emang sudah saya kombinasi jadi kalau datagridview anda tidak sama persis dengan gambar di atas jangan marah ya. Sekian dari saya, moga2 bermanfaat. Bila ada pertanyaan2, post komen aja langsung. 😀