Reputation: 341
I have an ObservableCollection<T>
that holds one type of object. I need this to be the source for several list controls but I also want to transform the data. For simplicity, imagine I have an ObservableCollection<int>
and want to get an ICollectionView
that returns strings - maybe just the integer converted to a string.
Is there a way to create such a view?
Something nice like:
var view = new MagicalCollectionView(myCollection, x => x.ToString())?
Upvotes: 0
Views: 811
Reputation: 37780
Collection views are about sorting, filtering, grouping. They are not about data transformation.
Actually, there's no direct need in such collection in your task interpretation. You just need to set up view properly, e.g. providing correct DataTemplate
for items in your source collection:
public class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class MyViewModel
{
public ObservableCollection<MyEntity> Entities { get; private set; }
public ICollectionView EntitiesView
{
if (view == null)
{
view = new ListCollectionView(Entities);
}
return view;
}
private ICollectionView view;
}
XAML:
<DataTemplate DataType="{x:Type local:MyEntity}">
<!-- This "transforms" visual representation of your entity, but the entity itself (and its container) remains unchanged -->
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
Update. According to you comment, I'd wrap entities into view models. Moreover, this is a purpose of view models:
public class MyEntityViewModel
{
private readonly MyEntity model;
public MyEntityViewModel(MyEntity model)
{
this.model = model;
}
public int MyInt
{
get { return model. // some logic to retrieve int ... }
}
public string MyString
{
get { return model. // some logic to retrieve string ... }
}
}
Then, instead of collection of models, I'd bind the control to the collection of view models:
public class MyViewModel
{
public MyViewModel(ICollection<MyEntity> entities)
{
this.Entities = new ObservableCollection<MyEntityViewModel>(entities.Select(e => new MyEntityViewModel(e)));
// this will keep two collections synchronized:
this.Entities.CollectionChanged += (sender, args) =>
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
entities.Add((MyEntity)e.NewItems[0]);
break;
case NotifyCollectionChangedAction.Remove:
entities.Remove((MyEntity)e.OldItems[0]);
break;
case NotifyCollectionChangedAction.Replace:
entities.Remove((MyEntity)e.OldItems[0]);
entities.Add((MyEntity)e.NewItems[0]);
break;
case NotifyCollectionChangedAction.Reset:
entities.Clear();
break;
}
}
}
public ObservableCollection<MyEntityViewModel> Entities { get; private set; }
}
This will keep your data class clear from extra properties, which are intended for view only.
Upvotes: 1
Reputation: 45253
I mostly agree with Dennis, however, using a binding converter to do the final transformation of the underlying bound value might help you in this situation.
I assume you have one collection of types and want different, live, projections of the data in different places.
You could bind to the same collection in each case and 'insert' a different custom converter for each case, probably in a custom DataTemplate.
http://www.silverlightshow.net/items/Data-Conversion-in-Silverlight-2-Data-Binding.aspx
Silverlight demo, but its the same.
Upvotes: 0
Reputation: 743
You can do a projection with LINQ
myCollection.Select(x=> int.Parse(x))
Will parse each element of your collection and return an integer
Upvotes: 0