When I add an item to the CheckedListBox list box I also want to store a reference to another object. I tried adding a new instance of this object to the CheckedListBox.
public class CheckedListBoxExtention : CheckedListBox
{
private ReferenceItem _referenceItem;
public ReferenceItem storedItem
{
get { return _referenceItem; }
set { _referenceItem = value; }
}
public CheckedListBoxExtention(ReferenceItem storedItem)
{
_referenceItem = storedItem;
}
}
This works in that later when I foreach though the items in CheckedListBox I have a reference to the _referenceItem object. However, when I add items like this, CheckedListBox shows up as blank (the list in the GUI itself). So I am trying to find a way to override the item text or something like that.
This is the code I used to fix the problem
class ReferenceItemWrapper
{
private ReferenceItem _item;
public ReferenceItemWrapper(ReferenceItem item)
{
_item = item;
}
public ReferenceItem getItem
{get {return _item;}}
public override string ToString()
{
return _item.ToString();
}
}
I am a bit new to wrappers. Why exactly did it work after it was wrapped when it did not work when I added the ReferenceItem directly to the CheckedListBox?
The CheckedListBox uses the ToString method of the objects in the list to populate the captions in the box. Rather than extend the CheckedListBox, just create a wrapper class that lets you store both your reference and a caption, and implements a ToString method which returns your caption. Just create one of your wrapper objects, stick the text in it, stick your reference in it, then add the wrapper object to the list box.
Related
I know that you can set up a ListBox to sort automatically. Is there a way to "catch" the sorting so that when the ListBox swaps the position of two items so that I can do the same reordering on another list box? I want sort one list box by by value but keep those values at the same relative index locations compared to another ListBox somewhere else.
I could write a routine to bubble sort the list so that I could make the changes myself, but it I am wondering if there is a more automated since I will likely have to do this at a few different places in the program.
Unfortunately, the Sorted property does not use the IComparable interface implementation just sorts based on the result of ToString of the items. But instead of setting the Sorted property, you can use a sorted data source (a List<>, for example).
Create a wrapper class for the items in the ListBox and implement the IComparable<T> interface on it. Populate a List<> with these ListBoxItem instances, then call the Sort method on the list. Thus you will able to dispatch the CompareTo calls.
public partial class Form1 : Form
{
private class ListBoxItem<T> : IComparable<ListBoxItem<T>>
where T : IComparable<T>
{
private T item;
internal ListBoxItem(T item)
{
this.item = item;
}
// this makes possible to cast a string to a ListBoxItem<string>, for example
public static implicit operator ListBoxItem<T>(T item)
{
return new ListBoxItem<T>(item);
}
public override string ToString()
{
return item.ToString();
}
public int CompareTo(ListBoxItem<T> other)
{
return item.CompareTo(other.item); // here you can catch the comparison
}
}
public Form1()
{
InitializeComponent();
var items = new List<ListBoxItem<string>> { "Banana", "Apple"};
items.Sort();
listBox1.DataSource = items;
}
I need to derive a class from ComboBox and change its Items property. Here is my code:
public class MyComboBox2 : ComboBox
{
private MyObjectCollection MyItems;
public MyComboBox2()
{
MyItems = new MyObjectCollection(this);
}
//new public ComboBox.ObjectCollection Items
new public MyObjectCollection Items
{
get {
return MyItems;
}
}
}
public class MyObjectCollection : ComboBox.ObjectCollection
{
public MyObjectCollection(ComboBox Owner) : base(Owner)
{
}
new public int Add(Object j)
{
base.Add(j);
return 0;
}
}
As you can see, I am creating a new class MyComboBox2 derived from ComboBox. This class is supposed to have a new Items property, which would be of type MyObjectCollection rather than ComboBox.ObjectCollection. I have a comboBox called myComboBox21 on the form of type MyComboBox2. When I want to add a new object to my ComboBox, I would execute code like this: myComboBox21.Items.Add("text");
In this case, I end up executing the Add method of MyObjectCollection that I implemented myself. However, the ComboBox on the form does not end up containing value 'text'. I am attaching screenshot of debugger showing ComboBox values. MyComboBox21 contains Items Property (which does contain "text", as shown in screenshot "2.png"), and it contains base.Items (which does not contain "text" as shown in "1.png"). So, apparently, MyComboBox21 contains its own Items property (which I can insert to), and its base class's Items property, which gets displayed in the Windows Form. What can I do so that I can successfully add to comboBox with my own method? Since my ComboBox has 2 Items properties, can I specify which Items property's values should be shown in ComboBox?
Just by looking very quickly on the code:
The original Item index is declared as
virtual Object this[int index] {...}
Does the new keyword maybe be exchanged by override in your implementation in order to make the runtime pick the intended code?
I have a app that makes use of the PropertyGrid in C#/.NET
the PropertGrid holds onto the MyAppObject class/object shown below..
class MyAppObject
{
private List<MyObject> oItems;
public List<MyObject> Items
{
get { return this.oItems; }
}
}
And so far it works well, nice and simple. I want the property grid to allow users to view the items, which it does well, however when you select the property in the PropertyGrid the dialog also allows to add more List<MyObject> items.
I do not want this, I only want to have the ability to show the items, not edit them.
I thought by not providing the setter (set { this.oItems = value; }):
then it wouldnt allow the add button.
Hope this makes sense, The screenshots shows the dialog, and I circled the buttons I want to remove.
thanks
If you expose it as a read-only list, it should do what you need:
[Browsable(false)]
public List<MyObject> Items
{
get { return this.oItems; }
}
// this (below) is the one the PropertyGrid will use
[DisplayName("Items")]
public ReadOnlyCollection<MyObject> ReadOnlyItems
{
get { return this.oItems.AsReadOnly(); }
}
Note that the members of individual objects (MyObject instances) will still be editable, unless you decorate them as [ReadOnly(true)].
As you note, the setter is not necessary to add/remove/edit items. That is because the grid still has full access to the .Add, .Remove and indexer (list[index]) operations.
This is a slightly tricky one; the solution involves building with the full .NET Framework (since the client-only framework doesn't include System.Design). You need to create your own subclass of CollectionEditor and tell it what to do with the temporary collection after the UI is finished with it:
public class MyObjectEditor : CollectionEditor {
public MyObjectEditor(Type type) : base(type) { }
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
return ((MyObject)context.Instance).Items;
}
}
Then you have to decorate your property with the EditorAttribute:
[Editor(typeof(MyObjectEditor), typeof(UITypeEditor))]
public List<MyObject> Items{
// ...
}
Reference: What's the correct way to edit a collection in a property grid
Alternative:
return new ReadOnlyCollection(oItems);
OR
return oItems.AsReadOnly();
As you can see in the pic below, for a ListView Control you can add Items using the Properties pane.
How do I enable this kind of stuff for my UserControl?
I'm not getting anything when I search Google, but I'm probably not using the correct terms.
Does anybody know?
Thanks
You need to create a class that defines the object type that the collection ids composed of. A listView has ListViewItem objects. A TabControl has TabPage objects. Your control has objects which are defined by you. Let's call it MyItemType.
You also need a wraper class for the collection. A simple implementation is shown below.
public class MyItemTypeCollection : CollectionBase
{
public MyItemType this[int Index]
{
get
{
return (MyItemType)List[Index];
}
}
public bool Contains(MyItemType itemType)
{
return List.Contains(itemType);
}
public int Add(MyItemType itemType)
{
return List.Add(itemType);
}
public void Remove(MyItemType itemType)
{
List.Remove(itemType);
}
public void Insert(int index, MyItemType itemType)
{
List.Insert(index, itemType);
}
public int IndexOf(MyItemType itemType)
{
return List.IndexOf(itemType);
}
}
Finally you need to add a member variable for the collection to your user control and decorate it properly:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MyItemTypeCollection MyItemTypes
{
get { return _myItemTypeCollection; }
}
and you now have a simple interface that allows you to browse and edit the collection. Leaves a lot to be desired still but to do more you will have to learn about custom designers which can be difficult to understand and implement.
I have a custom control that has an Items property. I Have applied an EditorAttribute with a UITypeEditor of type CollectionEditor.
Collection Type:
[Serializable]
[Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
public class ListItemsCollection : CollectionBase
{
// methods
}
Property Declaration In The Control:
private new ListItemsCollection _Items;
[Editor(typeof(CollectionEditor), typeof(UITypeEditor))]
public new ListItemsCollection Items
{
get
{
return _Items;
}
set
{
_Items = value;
// do other UI changes
}
}
Problem:
When I drop this control to the designer surface, I am able to add items to the Items property using the PropertyGrid. But, the when I click the Ok button of the CollectionEditor the setter of the Items property is not getting called.
AFAIK when a value is returned from the EditValue method of a UITypeEditor class the setter block of the property is supposed to be called.
This is driving me insane. I even tried adding Event's to the ListItemsCollection, so that when Items are added, I can whatever I want with the control's ui.
This is not supposed to be hard. What am I doing wrong?
I try to reprodeuce your situation: using following code, I get a message box showing whenever I edit the list from VS property window. Beware that you have to create the list by yourself. If you don't create it, VS create a temp list which you can edit from property window, but does not set your property to this list (so your setter will never be called)
public UserControl1()
{
InitializeComponent();
list = new BindingList<ListViewItem>();
list.ListChanged += new ListChangedEventHandler(list_ListChanged);
}
void list_ListChanged(object sender, ListChangedEventArgs e)
{
MessageBox.Show(e.ListChangedType.ToString());
}
private BindingList<ListViewItem> list;
public BindingList<ListViewItem> List1
{
get { return list; }
}
Collection properties should be read-only. It's the collection that is retrieved through the getter, and adjusted. The setter never enters into it, because that would mean setting a new collection.