Search code examples
c#winformsdatarepeater

Remove DataRepeater Control bottom line in Winforms


how can I remove the bottom border line of data control item in DataRepeater control:

enter image description here


Solution

  • The separator which you see in DataRepeater control between items, is a drawing on non-client area of DataRepeaterItem control.

    You can find those DataRepeaterItem and handle those WM_NCPAINT messages and draw a line with the same color as item BackColor or any other color which you want from (0, Height-1) to (Width-1, Height-1).

    Implementation

    To do so, we create a class deriving from NativeWindow which enables us to handle messages of another window, if we assign handle of other window to it:

    using Microsoft.VisualBasic.PowerPacks;
    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    public class DataRepeaterItemHelper : NativeWindow
    {
        private DataRepeaterItem item;
        private const int WM_NCPAINT = 0x85;
        [DllImport("user32.dll")]
        static extern IntPtr GetWindowDC(IntPtr hWnd);
        [DllImport("user32.dll")]
        static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
        public DataRepeaterItemHelper(DataRepeaterItem repeaterItem)
        {
            item = repeaterItem;
            this.AssignHandle(item.Handle);
        }
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_NCPAINT)
            {
                var hdc = GetWindowDC(m.HWnd);
                using (var g = Graphics.FromHdcInternal(hdc))
                using (var p = new Pen(item.BackColor, 1))
                    g.DrawLine(p, 0, item.Height - 1, item.Width - 1, item.Height - 1);
                ReleaseDC(m.HWnd, hdc);
            }
        }
    }
    

    Then we handle DrawItem event of DataRepeater and check if we didn't have created a DataRepeaterItemHelper for e.DataRepeaterItem we create one. It helps drawing the separator with the same color as item back color. Also after loading data into DataRepeater we should create DataRepeaterItemHelper for the first items which DrawItem event doesn't fire for them. To keep track of items which we created a DataRepeaterItemHelper for them, we keep handled items in a List<DataRepeaterItem>:

    new List<DataRepeaterItem> items = new List<DataRepeaterItem>();
    void HandleItem(DataRepeaterItem item)
    {
        if (items.Contains(item))
            return;
        var handler = new DataRepeaterItemHelper(item);
        items.Add(item);
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        //Load data and put data in dataRepeater1.DataSource
        var db = new TestDBEntities();
        this.dataRepeater1.DataSource = db.Category.ToList();
        this.dataRepeater1.Controls.OfType<DataRepeaterItem>().ToList()
            .ForEach(item => HandleItem(item));
        this.dataRepeater1.DrawItem += dataRepeater1_DrawItem;
    }
    void dataRepeater1_DrawItem(object sender, DataRepeaterItemEventArgs e)
    {
        HandleItem(e.DataRepeaterItem);
    }
    

    And here is the result:

    enter image description here

    Note:

    • When applying the solution, don't forget to attach Form1_Load event to Load event of form. You don't need to attach dataRepeater1_DrawItem to DrawItem event. It's been attached in Form1_Load using code.
    • You can encapsulate the logic in a derived DataRepeater control.