简体   繁体   中英

Change the customized ListView.Items after each build

I create a customized ListView that inherited from standard ListView in .NET to show an enum values as its Items ( WinForms project):

public class ScrapGroupsListView : ListView
{
    public event EventHandler SelectedColorChanged;

    private ScrapGroup _selectedGroup = ScrapGroup.None;

    [DefaultValue(ScrapGroup.None)]
    public ScrapGroup SelectedScrapGroup
    {
        get { return _selectedGroup; }
        set
        {
            if (_selectedGroup != value)
            {
                _selectedGroup = value;
                foreach (ListViewItem item in this.Items)
                {
                    if (item != null)
                    {
                        if (item.Tag != null)
                        {
                            var itemColor = (ScrapGroup)item.Tag;
                            if (itemColor == ScrapGroup.None) 
                                item.Checked = value == ScrapGroup.None;
                            else
                                item.Checked = value.HasFlag(itemColor);
                        }
                    }
                }

                if (SelectedColorChanged != null) 
                   SelectedColorChanged.Invoke(this, EventArgs.Empty);
            }
        }
    }

    public ScrapGroupsListView()
    {
        this.Items.Clear();
        this.CheckBoxes = true;
        this.HeaderStyle = ColumnHeaderStyle.None;
        this.View = View.List;

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

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

        var checkedScrapGroup = (ScrapGroup)e.Item.Tag;

        if (e.Item.Checked)
            if (checkedScrapGroup == ScrapGroup.None)
                SelectedScrapGroup = ScrapGroup.None;
            else
                SelectedScrapGroup |= checkedScrapGroup;
        else
            SelectedScrapGroup &= ~checkedScrapGroup;
    }
}

ScrapGrouop is my enum:

[Flags]
public enum ScrapGroup
{
    None=0,
    M=1,
    E=2,
    N=4,
    H=8
}

when I put the ScrapGroupsListView to my form, everything is OK and the control has no Items:

在此输入图像描述

But each time I build my project, the ScrapGroup values add to ScrapGroupsListView.Items (design-time):

after 1st build:

在此输入图像描述

after 2nd build:

在此输入图像描述

and so on.

Where is the problem?

Instead of constructor try:

protected override void OnCreateControl()
    {
        base.OnCreateControl();

        this.Items.Clear();
        this.CheckBoxes = true;
        this.HeaderStyle = ColumnHeaderStyle.None;
        this.View = View.List;

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

Every time you open the form in the VS designer it creates this code:

private void InitializeComponent()
{
    System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("None");
    System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("M");
    System.Windows.Forms.ListViewItem listViewItem3 = new System.Windows.Forms.ListViewItem("E");
    System.Windows.Forms.ListViewItem listViewItem4 = new System.Windows.Forms.ListViewItem("N");
    System.Windows.Forms.ListViewItem listViewItem5 = new System.Windows.Forms.ListViewItem("H");
    this.scrapGroupsListView1 = new ScrapGroupsListView();
    // 
    // scrapGroupsListView1
    // 
    this.scrapGroupsListView1.CheckBoxes = true;
    this.scrapGroupsListView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
    listViewItem1.StateImageIndex = 0;
    listViewItem1.Tag = ScrapGroup.None;
    listViewItem2.StateImageIndex = 0;
    listViewItem2.Tag = ScrapGroup.M;
    listViewItem3.StateImageIndex = 0;
    listViewItem3.Tag = ScrapGroup.E;
    listViewItem4.StateImageIndex = 0;
    listViewItem4.Tag = ScrapGroup.N;
    listViewItem5.StateImageIndex = 0;
    listViewItem5.Tag = ScrapGroup.H;
    this.scrapGroupsListView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
    listViewItem1,
    listViewItem2,
    listViewItem3,
    listViewItem4,
    listViewItem5});

This is why your items appear two times. First set from the constructor, second set from InitializeComponent() .

You can (and should) remove the code from InitializeComponent() but opening the form in the designer will screw it up again.

To prevent from this you can move the filling code to a separate method and invoke it from the form.

In your control:

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

public void Fill()
{
    this.Items.Clear();

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

In your form:

public MainForm()
{
    InitializeComponent();

    scrapGroupsListView1.Fill();
}

As a drawback at this solution you don't see your items in the designer.

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