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;
}
Related
Following this Topics Xceed WPF propertyGrid show item for expanded collection, how is it possible with XAML to sort the list by Name when Binding to Classes ?
Everytime I would like to add a new Item it should be immediately sorted. It doesn't work because if I use Classes.orderby(x=>x.name) it breaks all the bindings?
Hello After lot's of time the solution is at the same time and not, but here I gave you all the solution:
1) the getters and setter for your Observablecollection
private TheCollection yourcollection;
public TheCollection Yourcollection{
get{
yourcollection.CollectionChanged -= Your_CollectionChanged;
// use sort-Extension to sort pointprofil
yourcollection.Sort();
// read CollectionChange-Event
yourcollection.CollectionChanged += Your_CollectionChanged;
return yourCollection;
}
}
And your Collection have to inherit from ObservableCollection but at the Same time to get an Extension to sort()
here we go:
static class Extensions
public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable
{
List<T> sorted = collection.OrderBy(x => x).ToList();
for (int i = 0; i < sorted.Count(); i++)
collection.Move(collection.IndexOf(sorted[i]), i);
}
}
public class YourCollections : ObservableCollection<YourPoints>, ICustomTypeDescriptor, INotifyPropertyChanged
{
}
and YourPoints have to inherit from IComparable
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've done a lot of samples but nowhere encountered on my problem.
Namely, I would like to create a Grouped GridView, which consists of two groups, with the exception that each group is made up of completely different collection. For example, I would like to in the first group were Animals, and in the second, Cars.
I would also like to each of these groups had a different Template ;)
Make both your inner collection items derive from a common base class. When I did this I had an ItemBase class, and my Event, Story, and Party classes all derived from Item base.
Then, my groups collection items each contained a definition for Items of ObservableCollection. (I guess, thinking about it now, I could have used object as the implied base type, but I didn't) When coded this was actually populated with my derived classes, e.g.
Items.Add(new Event { Title = "I am an event" };
When you display the items in your grid, you will want to create a new class that derives from ItemTemplateSelector, and override the SelectTemplateCore(object item, DependencyObject container) method. My logic was as simple as
if(item is Event) { return EventTemplate; }
else if(item is Story) { return StoryTemplate }
else { return DefaultTemplate; }
(My Party item used the default template.)
Create a ObservableCollection and push your collection items.
Like This:
public class ScreenGroupModel
{
private ObservableCollection<object> _groupItems = new ObservableCollection<object>();
public ObservableCollection<object> GroupItems
{
get { return this._groupItems; }
}
public ScreenGroupModel()
{
}
public ObservableCollection<object> GetScreenGroups()
{
_groupItems.Add(new Class1);
_groupItems.Add(new Class2);
return _groupItems;
}
}
This Sample, simple collection showing. You can be used DataTemplateSelectors. Every kind of class, select a template.
ObservableCollection -> "object" type is important. Because, object is base type. You can be add, every kind class.
Regards ;)
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();
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.