Masoud Masoud - 2 months ago 11
C# Question

Binding an Enum property values to ListView.Items(WinForms)

I have following entity:

public class MyEntity
{
public int Id {get;set}
public Color SelectedColors
}


MyEntity
has
One-to-Many
relation with
Color
enum.

[Flags]
public enum Color
{
None=1,
White=2,
Red=3,
Blue=4
}


In the other word, every
myEntity
object may have one or more value from
Color
enum:

myEntity1.Color = Color.Red | Color.White;


I saved this data using
Entity Framewrok
:

using (var ctx = new MyContext())
{
var entity1 = new MyEntity { SelectedColors = Color.Blue | Color.White };
ctx.MyEntities.Add(entity1);
ctx.SaveChanges();
}


and read it using following code:

using (var ctx = new MyContext())
{
var entity1 = ctx.MyEntities.Find(id);
}


I want to show the selected colors by tick on
chechboxes
,

I used a
ListView
control(WinForms project) to do this job:

listView1.CheckBoxes = true;
listView1.HeaderStyle = None;
listView1.View = List;


and used following code to show all
Enum
values as
ListView.Items
:

foreach (var value in Enum.GetValues(typeof(Color)).Cast<Color>())
{
listView1.Items.Add(new ListViewItem()
{
Name = value.ToString(),
Text = value.ToString(),
Tag = value
});
}


enter image description here

Is there any way to bind
SelectedColors
values of my query result to
listView1.Items
?

[Updated]

I saw a solution in this link that Nick-K inherited a new control from
ListView
. I think that solution isn't good for me, because the inherited control take a
DataSource
and a
DataMember
, so what should I set for
DataMember
in my case(
SelectedColors
may have more than one value)?

Answer

If you want to edit your color, you can inherit your own control from ListView for that:

public class ColorListControl : ListView
{
    public event EventHandler SelectedColorChanged;

    private Color selectedColor = Color.None;

    [DefaultValue( Color.None )]
    public Color SelectedColor
    {
        get { return selectedColor; }
        set
        {
            if( selectedColor != value )
            {
                selectedColor = value;

                foreach( ListViewItem item in this.Items )
                {
                    Color itemColor = (Color)item.Tag;
                    if( itemColor == Color.None ) //see http://stackoverflow.com/questions/15436616
                        item.Checked = value == Color.None;
                    else
                        item.Checked = value.HasFlag( itemColor );
                }

                SelectedColorChanged?.Invoke( this, EventArgs.Empty );
            }
        }
    }

    public ColorListControl()
    {
        this.CheckBoxes = true;
        this.HeaderStyle = ColumnHeaderStyle.None;
        this.View = View.List;

        foreach( Color value in Enum.GetValues( typeof( Color ) ).Cast<Color>() )
        {
            this.Items.Add( new ListViewItem()
            {
                Name = value.ToString(),
                Text = value.ToString(),
                Tag = value
            } );
        }
    }

    protected override void OnItemChecked( ItemCheckedEventArgs e )
    {
        base.OnItemChecked( e );

        Color checkedColor = (Color)e.Item.Tag;

        if( e.Item.Checked )
            SelectedColor |= checkedColor;
        else
            SelectedColor &= ~checkedColor;
    }
}

And afterwards you can bind to its property SelectedColor:

public class MainForm : Form
{
    private ColorListControl listView1;

    public MainForm()
    {
        InitializeComponent();

        MyEntity entity = new MyEntity { SelectedColors = Color.Blue | Color.White };

        listView1.DataBindings.Add( nameof( listView1.SelectedColor ), entity, nameof( entity.SelectedColors ) );
    }

    private void InitializeComponent()
    {
        this.listView1 = new ColorListControl();
        this.SuspendLayout();
        // 
        // listView1
        // 
        this.listView1.Location = new System.Drawing.Point(16, 16);
        this.listView1.Name = "listView1";
        this.listView1.Size = new System.Drawing.Size(200, 128);
        this.listView1.TabIndex = 0;
        this.listView1.SelectedColorChanged += new System.EventHandler(this.listView1_SelectedColorChanged);
        // 
        // MainForm
        // 
        this.ClientSize = new System.Drawing.Size(318, 189);
        this.Controls.Add(this.listView1);
        this.Name = "MainForm";
        this.Text = "Form";
        this.ResumeLayout(false);

    }

    private void listView1_SelectedColorChanged( object sender, EventArgs e )
    {
        this.Text = listView1.SelectedColor.ToString();
    }
}

As @MSL already said: you need to define the numbers of your Color enum in powers of two (0, 1, 2, 4, 8, 16...). See https://msdn.microsoft.com/library/system.flagsattribute.aspx

To compile this example you need C# 6.0 / Visual Studio 2015. Otherwise you have to replace nameof( listView1.SelectedColor ) with "SelectedColor".

Instead of using a ListView you can consider using a CheckedListBox as well.