C# WinForms ListView Item Count Change Event - c#

Is there an event in Win Forms that can fire when the count of items in ListView change? I tried Size and Text - oddly enough they "sorta" worked but not always...
Im trying to trigger a label to update with the count of the listview items as it changes without manually doing that in a hundred methods.

If you are not using a bound datasource you can create a wrapper around the ListView Control and add a Method and an Event to fire off an event on adding an item to your ListView Collection.
Custom ListView
public class customListView : ListView
{
public event EventHandler<CustomEventArgs> UpdateListViewCounts;
public void UpdateList(string data)
{
// You may have to modify this depending on the
// Complexity of your Items
this.Items.Add(new ListViewItem(data));
CustomEventArgs e = new CustomEventArgs(Items.Count);
UpdateListViewCounts(this, e);
}
}
public class CustomEventArgs : EventArgs
{
private int _count;
public CustomEventArgs(int count)
{
_count = count;
}
public int Count
{
get { return _count; }
}
}
Example Usuage
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
customListView1.UpdateListViewCounts+=customListView1_UpdateListViewCounts;
}
private void customListView1_UpdateListViewCounts(object sender, CustomEventArgs e)
{
//You can check for the originating Listview if
//you have multiple ones and want to implement
//Multiple Labels
label1.Text = e.Count.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
customListView1.UpdateList("Hello");
}
}

Related

C# Windows Form Application ListView: How do I force the ListView to not update?

I know that you can forcibly refresh the ListView using the method ListView.Refresh(). However, how do I forcibly stop the ListView from updating its list every time I insert an object (for design purposes)?
Code:
string[] newData = { //Some strings };
ListViewItem newRow = new ListViewItem(newData);
listView1.Items.Add(newRow);
The above will insert a new row into my listView1 and listView will automatically update its list and add that new item at the bottom-most row. I want to prevent the automatic adding of data into my visual list, I want to only update the data on the click of a button I've provided.
So what you can do is create a class that will manage your state for you:
public class ListViewStateHelper
{
private readonly ListView _listView;
private readonly List<string> _items;
public ListViewStateHelper(ListView listView)
{
_listView = listView;
_items = new List<string>();
}
public void AddItem(string value)
{
_items.Add(value);
}
public void DeleteItem(string value)
{
_items.Remove(value);
}
public void Refresh()
{
_listView.Items.AddRange(_items.Select(i => new ListViewItem(i)).ToArray());
}
}
then create a global variable and initialize it
private readonly ListViewStateHelper _stateHelper;
public Form1()
{
InitializeComponent();
_stateHelper = new ListViewStateHelper(listView1);
}
then have your event handlers call it:
private void add_Click(object sender, EventArgs e)
{
_stateHelper.AddItem("a");
}
private void delete_Click(object sender, EventArgs e)
{
_stateHelper.DeleteItem("a");
}
private void refresh_Click(object sender, EventArgs e)
{
_stateHelper.Refresh();
}
Or you can simply just create a global variable that will hold your datasource and work against it, then you don't need the state helper class.

Access listbox from another class?

I made a class so when the user selects item from listbox it uninstalls that item, except the problem is I can't access the list box. I tried public aswell, but in the code of form1.cs the only thing clostest to that list box is
keep in mind name of listbox is ProgramslistBox
Ok guys I re edited this post;
private void button1_Click(object sender, EventArgs e)
{
if(ProgramsListbox.SelectedIndex == -1)
{
MessageBox.Show("Please select an item to uninstall!");
}
else
{
ProgramsListbox_SelectedIndexChanged("",EventArgs.Empty);
}
}
this code is the FORM1.CS class, and I have another class called UninstallItem.cs is where I want my code to be, this below is my other class
namespace PC_TECH_Registery_Cleaner
{
class UninstallItem
{
public void uninstallSelectedItem()
{
Form1 c = new Form1();
}
}
}
And this below is still in my FORM1.CS class, I was experimenting with it :
public void ProgramsListbox_SelectedIndexChanged(object sender, EventArgs e)
{
//this will access the Uninstall item class so we can uninstall selected item.
UninstallItem c = new UninstallItem();
c.uninstallSelectedItem();
}
Within your Form1.cs create instance of UnIstallItem class and use it. Then on Button Click call "RemoveSelected" method of UnInstaItem class by passing programsListBox to it and it should remove the selected item.
public class Form1:Form
{
ListBox ProgramsListbox;
UninstallItem unistall;
public Form1(){
InitializeComponent();
uninstall = new UninstallItem();
button1.Click+= button1_Click;
}
void button1_Click(object sender, EventArgs e){
unistall.RemoveSelected(ProgramsListbox);
}
}
Then in your external class;
public class UninstallItem{
public UninstallItem{}
public void RemoveSelected(ListBox list)
{
if(list.SelectedIndex==-1)
{
MessageBox.Show("Please Select Item from List");
return;
}
list.Items.RemoveAt(list.SelectedIndex);
}
}
The 2 easy ways to think about this are either
Call the method in your class from the event handler in your form
Have a method on your class which matches the signature of an event handler, and subscribe to the event.
The first requires no major change
private MyClass myClass = new MyClass();
public void ProgramsListbox_SelectedIndexChanged(object sender, EventArgs e)
{
myClass.DoSomething();
}
The second requires your class to have a specific method that matches the signature of that event handler currently in your form
public class MyClass
{
public void DoSomething(object sender, EventArgs e)
{
var listBox = (ListBox)sender;
// read selected index perhaps, or selected item maybe
}
}
And then in your form
private MyClass myClass = new MyClass();
protected override void OnLoad(EventArgs e)
{
this.ProgramsListBox.SelectedIndexChanged += myClass.DoSomething;
}

C# removing a control from a parent container and List

I have 2 controls that inherit UserControl
one is a container and the other is a collection of basic text boxes lables etc. hereby labeled as ContainerControl and ComboControl.
ContainerControl contains a List<ComboControl> and a foreach loop that adds them to a FlowLayoutPanel. ComboControl has a button that I would like to be used to clear itself from its parent's List.
I am not sure what the best way of doing this would be. this.parent and cast to ContainerControl or would Dispose() work? I'm fairly sure I could pass a ref to the List, but that sounds needlessly messy...
public partial class ContainerControl : UserControl
{
List<ComboControl> ComboControls = new List<ComboControl>();
...
//procederaly generate and fill ComboControls here
...
foreach (ComboControl value in ComboControls)
{
this.flowLayoutTable.Controls.Add(value);
}
...
}
public partial class ComboControl : UserControl
{
private void BtnDel_Click(object sender, EventArgs e)
{
//what goes here
}
...
}
Along the lines of what Zohar Peled said, something like this to remove a control to avoid leaking resources.
private void cleanup(Control c)
{
foreach(Control child in c.Controls)
cleanup(child);
if (c.Parent != null)
{
c.Parent.Controls.Remove(c);
c.Dispose();
}
}
For scenario like this i would use a custom event to send a delete request to parent control :
your ComboControl with Custom Event :
//Create Custom Event
public delegate void DeleteControlDelegate(object sender);
public partial class ComboControl : UserControl
{
//Custom Event to send Delete request
public event DeleteControlDelegate DeleteControlDelegate;
public ComboControl()
{
InitializeComponent();
}
//Invoke Custom Event
private void OnDeleteControl(object sender)
{
DeleteControlDelegate?.Invoke(sender);
}
private void BtnDel_Click(object sender, EventArgs e)
{
//On ButtonClick send Delete request
OnDeleteControl(this);
}
}
and in your ContainerControl subscribe to event of each ComboControl :
List<ComboControl> _comboControls = new List<ComboControl>();
public ContainerControl()
{
InitializeComponent();
}
private void ContainerControl_Load(object sender, EventArgs e)
{
_comboControls.Add(new ComboControl());
_comboControls.Add(new ComboControl());
_comboControls.Add(new ComboControl());
foreach (ComboControl value in _comboControls)
{
flowLayoutPanel.Controls.Add(value);
//Subscribe to Custom Event here
value.DeleteControlDelegate += Value_DeleteControlDelegate;
}
}
private void Value_DeleteControlDelegate(object sender)
{
//When Raised Delete ComboControl
flowLayoutPanel.Controls.Remove((Control) sender);
}
}

keeping only 5 items in a listbox

I want to create a simple listbox, which is binded to a linkedlist.
The list should only ever hold 5 items at any given time.
When a new item is added, it should check if item count >= 5 and then remove the last item and add the new item to the top.
To do this, I made this test app:
public partial class Form1 : Form
{
LinkedList<string> list01 = new LinkedList<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
list01.AddFirst("AAA");
list01.AddFirst("BBB");
list01.AddFirst("CCC");
listBox1.DataSource = new BindingSource(list01, "");
}
private void button1_Click(object sender, EventArgs e)
{
if (list01.Count >= 5)
list01.RemoveLast();
list01.AddFirst(DateTime.Now.ToString());
listBox1.DataSource = new BindingSource(list01, "");
}
}
It appears, when ever I add a new item, I have to keep setting the datasource to a new bindingsource for the added item to show on the U.I.
Is there way to initisalise one binding source, and when the items in it changes, auto update the listbox without having to set the datasource every time you add a new item?
You need a collection which implements collection changed notification. There are two options you have BindingList<T> and ObservableCollection<T>.
Pick any one, From your comment it seems you're just looking for AddFirst and RemoveLast. You can create a extension method yourself which does that.
public static class BindingListExtension
{
public static void AddFirst<T>(this BindingList<T> list, T item)
{
list.Insert(0, item);
}
public static void RemoveLast<T>(this BindingList<T> list)
{
list.RemoveAt(list.Count - 1);
}
}
Based on Sriram Sakthivel's suggestion, I have achieved my requirement like this:
public partial class Form1 : Form
{
BindingList<string> list01 = new BindingList<string>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listBox1.DataSource = list01;
list01.Add("AAA");
list01.Add("BBB");
list01.Add("CCC");
}
private void button1_Click(object sender, EventArgs e)
{
if (list01.Count >= 5)
list01.RemoveAt(4);
list01.Insert(0, DateTime.Now.ToString());
}
}

How to access selected index change on dropdown?

I am new to C# and I created a user control similar to the person from this thread:
add user control to a form
only, I used 4 dropdowns. I created a custom user control whose class is called CustomBaseUserControl.cs. It has all the selected index changed events for each dropdown. From the the form, call it TheFormControl, that the CustomBaseUserControl was dropped into, how do I access those event change values?
Thanks in advance!
If you need to retrieve selected index on TheFormControl, you could either
Use variables to store the value on CustomBaseUserControl, in this case you'll have to listen the SelectedIndexChanged events and updates your values.
Trigger a custom selected index changed from CustomBaseUserControl to TheFormControl
--
class CustomBaseUserControl: UserControl{
int idx1=-1;
public CustomBaseUserControl()
{
Initialize();
//Fill ComboBox
//Suscribe Event
combobox1.SelectedIndexChanged += combobox1_SelectedIndexChanged;
}
void combobox1_SelectedIndexChanged(object sender, EventArgs e)
{
int index = combobox1.SelectedIndex;
if (index != idx1)
{
idx1=index;
RaiseIndexChanged(e);
}
}
public virtual void RaiseIndexChanged(EventArgs ea)
{
var handler = OnIndexChanged;
if (OnIndexChanged != null)
OnIndexChanged(this, ea);
}
public event EventHandler OnIndexChanged;
}
Caller class would be
class TheFormControl: Form
{
CustomBaseUserControl cb;
public TheFormControl()
{
Initialize();
cb = new CustomBaseUserControl();
cb.OnIndexChanged +=cb_OnIndexChanged;
}
void cb_OnIndexChanged(object sender, EventArgs e)
{
// Here you know index has changed on CustomBaseUserControl
}
}

Categories

Resources