What object collection should I have to add objects? - c#

I'm using Prism in WPF.
I was watching the Prism starter kit, and it has a ICollectionView. In that collection, I need to add the object selected in it. What object (or collection) should I use to add objects?
I mean in the image, I have two listbox, in the first one I've got a readonly collection and the second one is a list where can add or remove objects.

Your List should be bound to an ICollectionView that wraps an ObservableCollection. When you add, you add to this Observable collection.
I.e
private readonly ObservableCollection<Stock> listToAddTo;
public ICollectionView List2 { get; private set; }
Constructor
listToAddTo = new ObservableCollection<Stock>();
List2 = CollectionViewSource.GetDefaultView(listToAddTo);
Where List2 is what is bound to

Related

Data Binding with a Sorted List

My UI has a ListBox which is bound to a Collection. Right now this happens to be an ObservableCollection
My objective is to add objects to this Collection via the UI, and have the ListBox dynamically update, all while maintaining a sorted Collection.
I am aware that there is some SortedView that I can use in WPF. But that is not what I want - I need the actual Collection to remain sorted because my business logic requires a sorted collection.
One way that I thought of, is to create my own Collection class which uses a SortedList internally, and implements the INotifyCollectionChanged interface and produces NotifyCollectionChangedEventArgs event when the internal list changes. Sounds like a lot of work!
Is there a simple solution that I've missed?
Depending on your exact needs, the simplest approach is to keep your ObservableCollection, but wrap in in a new property of type ICollectionView:
public class MyViewModel {
private CollectionViewSource _collectionViewSource;
public ICollectionView MyCollectionView => _collectionViewSource.View;
public MyViewModel(ObservableCollection<MyDataItem> dataItems) {
_collectionViewSource = new CollectionViewSource() { Items = dataItems };
//Add sorting here using _collectionViewSource.SortDescriptions.Add(...)
}
You can use the wrapper property to extract a sorted list as needed.
Okay so I ended up inheriting from ObservableCollection, and overriding the Add() method.
This did the trick for me. Now my list is always sorted, and the ObservableCollection is the one that Notifies the UI of changes.
public class MyCollection : ObservableCollection<Int32>
{
public new void Add(Int32 x)
{
base.Add(x);
var oldList = new ObservableCollection<Int32>(this.OrderBy(c=>c));
Clear();
foreach(var i in oldList)
{
base.Add(i);
}
}
}
I'm a beginner with C#, any feedback on the code is appreciated.

Are There Any CollectionViewSource Alternative with Generic?

For my WPF application, I need CollectionViewSource to enable selection, filtering, sorting, and grouping in a collection. But CollectionViewSource is not a type safe collection like IList, the property View.CurrentItem is an object for example. We need to cast the items if we use them.
Are there any CollectionViewSource alternatives that support Generic?
Or maybe anybody know the reason why CollectionViewSource is not a generic?
=============================
I made a generic CollectionViewSource based on standard CollectionViewSource.
Any comment whether it is a better alternative for collection class that is instantiated outside XAML? Or there is another better alternative?
Edit 1: Add Generic CollectionViewSource
namespace Data
{
using System.Collections.Generic;
using System.Linq;
using System.Windows.Data;
public class CollectionViewSource<T> : CollectionViewSource
{
public T CurrentItem => this.View != null ? (T)this.View.CurrentItem : default(T);
public new IEnumerable<T> Source
{
get
{
return (IEnumerable<T>)base.Source;
}
set
{
base.Source = value;
}
}
public IEnumerable<T> ViewItems => this.View != null ? Enumerable.Cast<T>(this.View) : (IEnumerable<T>)null;
public CollectionViewSource(IEnumerable<T> source)
{
this.Source = source;
}
public bool Contains(T item)
{
return this.View != null && this.View.Contains(item);
}
public IEnumerable<T> Groups()
{
return this.View.Groups.Cast<T>();
}
public void MoveCurrentTo(T item)
{
this.View?.MoveCurrentTo(item);
}
}
}
You can actually just bind to your ObservableCollection (or any collection) and then call CollectionViewSource.GetDefaultView for that collection instance, then apply a filter, and your DataGrid (or other items controls) will get filtered. This way you can have your cake and eat it too :-)
The reason for this, I suspect, is because WPF list controls never actually bind to normal .NET collections, but always call CollectionViewSource.GetDefaultView behind the scenes, and that seems to return the same instance as the one you already created, if you created one.
Codebehind:
MySourceCollection = new[]
{
new ViewModel(1, "first"),
new ViewModel(2, "second"),
new ViewModel(3, "third"),
new ViewModel(4, "fourth")
};
MyListView = CollectionViewSource.GetDefaultView(MySourceCollection);
MyListView.Filter = o => ((ViewModel)o).Number >= 3;
XAML:
<DataGrid ItemsSource="{Binding MySourceCollection}" />
Result:
I don't know whether this is recommended, but I don't see any problem yet. Just remember that if you reinitialize your source list, you have to call CollectionViewSource.GetDefaultView again and reapply your filters.
The reason why its not generic is that the type safety should be in your underlying collection not your view.
The CollectionViewSource is purely for formatting the display of the data, so like a combo and list controls are not typed neither is CollectionViewSource and for exactly the same reason, because they need to work with anything that is given to them
as an example you have a Students Collection, you want to display this in a combo but your also want to be able to select "NEW STUDENT" new student isn't a student so can't be added to the student collection but is a perfectly valid combo item so while the underlying collection has to be Type safe, enforcing the same on the combo is limiting and not protective, out side of your view your code really shouldn't care if values are sorted or not that's usually just a human thing
as for your generic CollectionViewSource, it depends how your are using it if its a good idea not however the type safety should be superflous because your underlying collection should already be doing this.
I would suggest having an ObservableCollection<T> as the source of your CollectionViewSource and then just forgetting about Type safing the display

Initialize a collection with a type from another collection

This might and impossible scenario and I may be trying to do something that I should not be doing in the first place but here it is.
I have a custom WPF Control which has two IEnumerable collections
The first collection (ItemsSource) is declared via the XAML and might be of any type of objects.
The second collection the one that I am implementing is again an IEnumerable which I want to initialize as ObservableCollection.
Here is my issue as I am restricted that both the collections are of the same type of objects (no I cannot use object as a type). For example the ItemsSource is of "MyItem" type objects and I want to initialize the second collection to be ObservableCollection().
Is this possible? Am i doing something that I should not be doing? Any hints will appreciated. On a side note if I pass the second collection via the XAML all is well, but I do not want to add such restriction to the feature I am implementing.
Edit:
Here are some code snippets to showcase the scenario:
The first collection, note that this collection is inherited from the System.Windows.Controls.ItemsControl class:
public IEnumerable ItemsSource { get; set; }
The second collection:
public IEnumerable SelectedItems
{
get
{
this.InitializeSelectedItemsCollectionIfRequired();
return (IEnumerable)GetValue(SelectedItemsProperty);
}
set
{
SetValue(SelectedItemsProperty, value);
}
}
private void InitializeSelectedItemsCollectionIfRequired()
{
if (this.GetValue(SelectedItemsProperty) == null)
{
// Here is where I want to initialize the second collection if it was not already set in via a Binding in the XAML
this.SelectedItems = new System.Collections.ObjectModel.ObservableCollection<"dont know how to pass correct type here">();
}
}
Since you don't know the exact type you could simply revert to the most basic type object
this.SelectedItems = new System.Collections.ObjectModel.ObservableCollection<object>();

Is INotifyPropertyChanged needed for binding ObservableCollection?

When I'm binding, say a Label to a string, I define the string this way:
private string _lbl;
public string Lbl
{
get
{
return = _lbl;
}
set
{
_lbl=value;
OnPropertyChanged("Lbl");
}
}
With the INotifyPropertyChanged interface implemented in my class.
Should I define the same way an ObservableCollection or I just could leave it this way?
public ObservableCollection<File> myFiles {get; set;}
As a general rule, I tend to define ObservableCollections like this:
private ObservableCollection<Item> _items;
public ObservableCollection<Item> Items
{
get { return _items ?? (_items = new ObservableCollection<Item>()); }
}
This is called "Lazy initialization", where the ObservableCollection is only instantiated where it is first accessed.
This is a good way to ensure your Collection Will Never Be Null
Notice that it does not have a setter, because an ObservableCollection is not something that you usually assign to. Instead, if you want to completely replace items, do:
Items.Clear();
//... Add all the new items
This avoids WPF having to rebind all the CollectionChanged events and stuff in order to listen to and react to items added / removed from the collection. You only have 1 instance of the collection, forever. Whatever items you place on it, the collection remains the same.
This is not to be confused with the PropertyChange notification inside the ITEMS of the collection. WPF handles these concepts separately, because property changes are notified by ITEMS, but Collection changes (Item added or removed) are notified by the Collection itself.
If the myFiles property can change, then yes, you should raise the PropertyChanged event. If not (that is, if it's got no setter, or it has a private setter that is only set once, e.g. in the constructor), then you don't need to raise the event. The collection itself will raise its own PropertyChanged and CollectionChanged events, but the object that contains the collection must raise PropertyChanged if the property that contains the collection changes.

Multiple Listboxes bound to same List

I am trying to bind several ListBoxs to a List. When a ListBox on one form is updated, I want it to update the other ListBox, too.
The problem I am running into is that it doesn't seem to update the view on the ListBox when I update the underlying List. If I look at the ListBox.Items in debug, I can see that all the items I add are there, but are not being displayed. Additionally, when I open another form that displays the List on a ListBox, it does correctly display whatever items had already been added.
private List<String> _list;
public Form1()
{
InitializeComponent();
_list = StaticInstanceOfList.GetInstance();
listbox1.DataSource = _list;
}
public void AddStringToList(string value)
{
if (!_list.Contains(value))
{
_list.Add(value);
}
}
Try to use a BindingList<T> to store your items and then assign this list to both listboxes via the DataSource property.
Use a bindingSource and bind both listBoxes to that.

Categories

Resources