简体   繁体   中英

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
                           });
}

在此处输入图片说明

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)?

ListView class does not support design time binding

Look at this

http://www.codeproject.com/Articles/10008/Data-binding-a-ListView

First of all your enum should be like this:

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

Use this Property

public List<string> SelectedColorsList
{
    get
    {
        return SelectedColors.ToString()
               .Split(new[] { ", " }, StringSplitOptions.None)
               .ToList();
    }
    set
    {
        if (value == null)
        {
             this.SelectedColors = MyColors.None;
             return;
        }

        int s = 0;
        foreach (var v in value)
        {
            s += (int)Enum.Parse(typeof(MyColors), v);
        }

        this.SelectedColors = (MyColors)s;
    }
}

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:

public class ColorListControl : CheckedListBox
{
    public event EventHandler SelectedColorChanged;

    private Color selectedColor = Color.None;

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

                for( int i = 0; i < this.Items.Count; i++ )
                {
                    Color itemColor = (Color)this.Items[i];
                    if( itemColor == Color.None )
                        this.SetItemChecked( i, value == Color.None );
                    else
                        this.SetItemChecked( i, value.HasFlag( itemColor ) );
                }

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

    public ColorListControl()
    {
        CheckOnClick = true;

        foreach( Color value in Enum.GetValues( typeof( Color ) ) )
            this.Items.Add( value );
    }

    protected override void OnItemCheck( ItemCheckEventArgs ice )
    {
        base.OnItemCheck( ice );

        Color checkedColor = (Color)this.Items[ice.Index];

        if( ice.NewValue == CheckState.Checked )
            SelectedColor |= checkedColor;
        else
            SelectedColor &= ~checkedColor;
    }
}

If you only want to view the colors, you can just set Checked -property of ListViewItem without any databinding or custom control:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM