Search code examples
c#.netwinformsobjectlistview

FastObjectListView formatting a button column


I have a button column in my FastObjectListView that acts as a toggle for my specific variable. When I press the button I want it to essentially toggle between these two states:ON and OFF states

The logic behind the toggling is not hard, its just that I can't figure out for the life of me how to change the color of a button in a column or change the horizontal alignment

I have the following ButtonClick event:

folvOutputs.ButtonClick += delegate (object sender, CellClickEventArgs e)
{
    ioClass ioObj = e.Model as ioClass;
    bool bOn = false;
    if (ioObj.ioStatus == 1)
    {
        bOn = true;
    }
    e.Item.ForeColor = Color.Red;
    e.SubItem.ForeColor = Color.Red;
   
    sendCANMessageToSwitch((byte)ioObj.ioSourceAddress, (byte)ioObj.ioSubID, bOn);
    folvOutputs.RefreshObject(ioObj);

};

This is not the intended logic, but merely a test to see if the color would actually change. It did not. I also have this FormatCellEvent with UseCellFormatEvents enabled:

private void folvOutputs_FormatCell(object sender, BrightIdeasSoftware.FormatCellEventArgs e)
{
    if (e.SubItem is null) return;
    if (e.ColumnIndex == 6)
    {
        ioClass ioObj = (ioClass)e.Model;
        if (ioObj.ioStatus == 1)
        {
            e.SubItem.ForeColor = Color.Green;
        }
        else
        {
            e.SubItem.ForeColor = Color.Red;
        }
    }
}

Edit:

This is what I ended up going with, I don't know if its the best way but it works for now.:


    public override void Render(Graphics g, Rectangle r)
    {
        base.Render(g, r);
        StringFormat fmt = new StringFormat(StringFormatFlags.NoWrap);
        fmt.LineAlignment = StringAlignment.Center;
        fmt.Trimming = StringTrimming.EllipsisCharacter;

        SolidBrush brush;
        Pen topLeft, bottomRight;
        if (GetText() == "OFF")
        {
            fmt.Alignment = StringAlignment.Far;
            brush = new SolidBrush(Color.LightGray);
            topLeft = new Pen(Color.Black, 2);
            bottomRight = new Pen(Color.Black, 2);
        }
        else
        {
            fmt.Alignment = StringAlignment.Near;
            brush = new SolidBrush(Color.ForestGreen);
            topLeft = new Pen(Color.White, 2);
            bottomRight = new Pen(Color.Black, 2);
        }
        g.FillRectangle(brush, r);
        g.DrawRectangle(topLeft, r);
        g.DrawRectangle(bottomRight, new Rectangle(r.X + 1, r.Y + 1, r.Width - 2, r.Height - 2));
        g.DrawString(this.GetText(), this.Font, this.TextBrush, r, fmt);

        brush.Dispose();
        topLeft.Dispose(); 
        bottomRight.Dispose();
    }


Solution

  • If you have IsButton on the row set to true, the OLV probably renders a button using the default ColumnButtonRenderer.

    Maybe you can implement your own renderer or derive from the existing one. This would give you control over text color an position.

    Similar to this:

    public class MyCustomRenderer : BaseRenderer 
    {
        public override void Render(Graphics g, Rectangle r)
        {
            
            var fmt = new StringFormat(StringFormatFlags.NoWrap);
            fmt.LineAlignment = StringAlignment.Center;
            fmt.Trimming = StringTrimming.EllipsisCharacter;
            
            // Formatting depending on object state
            var myItem = (Item)RowObject;      
            fmt.Alignment = myItem.IsEnabled ? StringAlignment.Near : StringAlignment.Far;
            var color = myItem.IsEnabled ? Brushes.Black : Brushes.Red;
            
            g.DrawString(GetText(), ListView.Font, color, r, fmt);
        }
    }
    

    You can assign the renderer to a column using the column.Renderer property.

    However, for simplicity, you should consider not using a button control or custom renderer at all. Just handle the cell-click to toggle object state and then use FormatRow or FormatCell event to adjust alignment and color.