locked
Sorting objects that explicitly implement an interface - CollectionView, CollectionViewSource, Binding RRS feed

  • Question

  • Hi All,

    We have recently implemented a system in which a listview is bound to a collection of objects that all explicityly implement a common interface. Similar to Lee Campbell's example;

    http://leecampbell.blogspot.com/2008/09/generic-binding-in-wpf-through-explicit.html

    Unfortunately this breaks any sorting that relies on the CollectionView/CollectionViewSource classes. Consider the following;

    using System;  
    using System.Collections.Generic;  
    using System.Windows.Data;  
    using System.ComponentModel;  
     
    namespace ConsoleApplication8  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                CollectionViewSource viewSource = new CollectionViewSource();              
                viewSource.Source = new List<IFruit> { new Orange(), new Apple() };  
     
                viewSource.View.SortDescriptions.Add(new SortDescription("Colour", ListSortDirection.Ascending));  
                foreach (var f in viewSource.View)  
                    Console.WriteLine(((IFruit)f).Colour);  
            }  
        }  
     
        class MyCollectionViewSource : CollectionViewSource  
        {  
              
        }  
     
        class Apple : IFruit  
        {  
            //public string Colour  
            string IFruit.Colour  
            {  
                get { return "zRed/Green"; }  
            }  
        }  
     
        class Orange : IFruit  
        {  
            //public string Colour  
            string IFruit.Colour  
            {  
                get { return "Orange"; }  
            }  
        }  
     
        interface IFruit  
        {  
            string Colour { get; }  
        }  
    }  
     

    I have not investigated but I suspect my options are;

    1. Subclass CollectionView
    2. Refactor & not use explicit interfaces

    Cheers,
    James Miles
    • Edited by James Miles Thursday, October 23, 2008 7:48 AM
    Thursday, October 23, 2008 6:56 AM

Answers

  • One possible solution is to create an adapter collection like this;

    using System;  
    using System.Collections.Generic;  
    using System.Windows.Data;  
    using System.ComponentModel;  
    using System.Collections.ObjectModel;  
     
    namespace ConsoleApplication8  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                CollectionViewSource viewSource = new CollectionViewSource();  
                viewSource.Source = new FruityCollection() { new Orange(), new Apple() };  
     
                viewSource.View.SortDescriptions.Add(new SortDescription("Colour", ListSortDirection.Ascending));  
                foreach (var f in viewSource.View)  
                    Console.WriteLine(((IFruit)f).Colour);  
            }  
        }  
     
        class FruityCollection : ObservableCollection<HardFruit> // adapts explicit implementations of IFruit objects into a collection or "hard fruit"  
        {  
            public void Add(IFruit fruit)  
            {  
                base.Add(new HardFruit(fruit));  
            }  
     
            public void AddRange(IEnumerable<IFruit> fruit)  
            {  
                foreach (var f in fruit)  
                    Add(f);  
            }  
        }  
     
        class HardFruit : IFruit// wraps any implementation of IFruit in an implicit implementation  
        {  
            private IFruit _softFruit;  
            public HardFruit(IFruit fruit)  
            {  
                _softFruit = fruit;  
            }  
     
            public string Colour // implicitly implement IFruit  
            {  
                get { return _softFruit.Colour; }  
            }  
        }  
     
        class Apple : IFruit  
        {  
            string IFruit.Colour // explicity implement IFruit  
            {  
                get { return "aRed/Green"; }  
            }  
        }  
     
        class Orange : IFruit  
        {  
            string IFruit.Colour // explicity implement IFruit  
            {  
                get { return "Orange"; }  
            }  
        }  
     
        interface IFruit  
        {  
            string Colour { get; }  
        }  
    }  
     

    This is kind of neat, because it protects us against other unforseen problems related to explicitly implemented interfaces. We have already hit Binding & Sorting... who knows what's down the track.

    Any other ideas?
    James
    • Edited by James Miles Saturday, October 25, 2008 7:32 AM
    • Marked as answer by Marco Zhou Tuesday, October 28, 2008 7:50 AM
    Thursday, October 23, 2008 8:45 AM

All replies

  • One possible solution is to create an adapter collection like this;

    using System;  
    using System.Collections.Generic;  
    using System.Windows.Data;  
    using System.ComponentModel;  
    using System.Collections.ObjectModel;  
     
    namespace ConsoleApplication8  
    {  
        class Program  
        {  
            static void Main(string[] args)  
            {  
                CollectionViewSource viewSource = new CollectionViewSource();  
                viewSource.Source = new FruityCollection() { new Orange(), new Apple() };  
     
                viewSource.View.SortDescriptions.Add(new SortDescription("Colour", ListSortDirection.Ascending));  
                foreach (var f in viewSource.View)  
                    Console.WriteLine(((IFruit)f).Colour);  
            }  
        }  
     
        class FruityCollection : ObservableCollection<HardFruit> // adapts explicit implementations of IFruit objects into a collection or "hard fruit"  
        {  
            public void Add(IFruit fruit)  
            {  
                base.Add(new HardFruit(fruit));  
            }  
     
            public void AddRange(IEnumerable<IFruit> fruit)  
            {  
                foreach (var f in fruit)  
                    Add(f);  
            }  
        }  
     
        class HardFruit : IFruit// wraps any implementation of IFruit in an implicit implementation  
        {  
            private IFruit _softFruit;  
            public HardFruit(IFruit fruit)  
            {  
                _softFruit = fruit;  
            }  
     
            public string Colour // implicitly implement IFruit  
            {  
                get { return _softFruit.Colour; }  
            }  
        }  
     
        class Apple : IFruit  
        {  
            string IFruit.Colour // explicity implement IFruit  
            {  
                get { return "aRed/Green"; }  
            }  
        }  
     
        class Orange : IFruit  
        {  
            string IFruit.Colour // explicity implement IFruit  
            {  
                get { return "Orange"; }  
            }  
        }  
     
        interface IFruit  
        {  
            string Colour { get; }  
        }  
    }  
     

    This is kind of neat, because it protects us against other unforseen problems related to explicitly implemented interfaces. We have already hit Binding & Sorting... who knows what's down the track.

    Any other ideas?
    James
    • Edited by James Miles Saturday, October 25, 2008 7:32 AM
    • Marked as answer by Marco Zhou Tuesday, October 28, 2008 7:50 AM
    Thursday, October 23, 2008 8:45 AM
  • using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Data; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { CollectionViewSource viewSource = new CollectionViewSource(); viewSource.Source = new List<IFruit> { new Orange(), new Apple() }; viewSource.View.SortDescriptions.Add(new SortDescription("Colour", ListSortDirection.Ascending)); foreach (var f in viewSource.View) Console.WriteLine(((IFruit)f).Colour); } } class MyCollectionViewSource : CollectionViewSource { } class Apple : IFruit { //public string Colour public string Colour { get { return "aRed/Green"; } } } class Orange : IFruit { //public string Colour public string Colour { get { return "Orange"; } } } interface IFruit { string Colour { get; } } } // - it works like a charm, so where is the problem ? (just specify Colour instead of IFruit.Colour .. if naming convention well set then no pb with name attributes collision.
    Friday, January 8, 2010 1:06 PM