none
Sort Combobox Items

    Question

  • Hi.

     

    I have a combo box created using xaml. I bind the item source to a xml document.

     

    <Items>

    <Item>
    <Name>David</Name>

    <Age>20</Age>

    </Item>

    <Item>
    <Name>Marcus</Name>

    <Age>25</Age>

    </Item>

    <Item>
    <Name>George</Name>

    <Age>25</Age>

    </Item>

    </Items>

     

     

    <ComboBox Name="cb1" ItemsSource="{Binding Source={StaticResource myList}, XPath=Items/Item}" DisplayMemberPath="Name"/>

     

    I would like to sort the combobox items so that the items are displayd in ascending order.  

     

    I manage to sort the above list by using SortDescription as below :

     

    SortDescription sd = new SortDescription("Name", ListSortDirection.Ascending);

     

    cb1.Items.SortDescriptions.Add(sd);

     

    The combobox will display the items in the following order.

     

    David

    George

    Marcus

     

    Now, when I add a node to the xml document, I added CData to handle invalid characters. The xml document will be updated as below :

     

    <Items>

    <Item>
    <Name>David</Name>

    <Age>20</Age>

    </Item>

    <Item>
    <Name>Marcus</Name>

    <Age>25</Age>

    </Item>

    <Item>
    <Name>George</Name>

    <Age>25</Age>

    </Item>

    <Item>
    <Name
    ><![CDATA[Peter&#M]]></Name>

    <Age>25</Age>

    </Item>

    </Items>

     

    When I do this, the sorting failed. The node with CData is always sorted to the top of the list.

     

    Peter&#M

    David

    George

    Marcus

     

     

    Any idea what I can do to solve this problem?

     

    Thanks.

     

    Tuesday, March 18, 2008 10:54 AM

Answers

  • The following code can workaround this issue:

    Code Snippet

    <Window x:Class="AnswerHarness2.SortXmlDataProblem"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=windowsbase"
        Title="SortXmlDataProblem">
      <Window.Resources>
        <XmlDataProvider x:Key="list" >
          <x:XData>
            <Items xmlns="">
              <Item>
                <Name>David</Name>
                <Age>20</Age>
              </Item>
              <Item>
                <Name>Marcus</Name>
                <Age>25</Age>
              </Item>
              <Item>
                <Name>George</Name>
                <Age>25</Age>
              </Item>
              <Item>
                <Name><![CDATA[Peter&#M]]></Name>
                <Age>25</Age>
              </Item>
            </Items>
          </x:XData>
        </XmlDataProvider>
        <CollectionViewSource
            Source="{Binding Source={StaticResource list}, XPath=Items/Item/Name}"
            x:Key="data"/>
      </Window.Resources>
      <ComboBox
          Name="cb1"
          Height="23"
          ItemsSource="{Binding Source={StaticResource data}}"/>
    </Window>

    public partial class SortXmlDataProblem : Window
    {
        public SortXmlDataProblem()
        {
            InitializeComponent();
            this.cb1.Loaded += delegate
            {
                CollectionViewSource cvs = this.TryFindResource("data") as CollectionViewSource;
                if (cvs != null)
                {
                    ListCollectionView view = cvs.View as ListCollectionView;
                    if (view != null)
                    {
                        view.CustomSort = new XmlComparer();
                    }
                }
            };
        }

        public class XmlComparer : IComparer
        {
            public Int32 Compare(Object x, Object y)
            {
                XmlElement a = x as XmlElement;
                XmlElement b = y as XmlElement;
                if (a != null && b != null)
                {
                    return String.Compare(a.InnerText, b.InnerText);
                }

                return -1;
            }
        }
    }


    Hope this helps
    Thursday, March 20, 2008 4:25 AM

All replies

  • Its sorting on the strings and this string begins with "<".  You will want to look at sorting another way.  You could write your own implemenation of Sort description.  The only major thing you want to do is to strip out the tags before sorting which is easy with a regular expression.  Your custom SortDescription could just do this then call teh base sortdescription to do the actual sort.
    Tuesday, March 18, 2008 1:02 PM
  • The following code can workaround this issue:

    Code Snippet

    <Window x:Class="AnswerHarness2.SortXmlDataProblem"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=windowsbase"
        Title="SortXmlDataProblem">
      <Window.Resources>
        <XmlDataProvider x:Key="list" >
          <x:XData>
            <Items xmlns="">
              <Item>
                <Name>David</Name>
                <Age>20</Age>
              </Item>
              <Item>
                <Name>Marcus</Name>
                <Age>25</Age>
              </Item>
              <Item>
                <Name>George</Name>
                <Age>25</Age>
              </Item>
              <Item>
                <Name><![CDATA[Peter&#M]]></Name>
                <Age>25</Age>
              </Item>
            </Items>
          </x:XData>
        </XmlDataProvider>
        <CollectionViewSource
            Source="{Binding Source={StaticResource list}, XPath=Items/Item/Name}"
            x:Key="data"/>
      </Window.Resources>
      <ComboBox
          Name="cb1"
          Height="23"
          ItemsSource="{Binding Source={StaticResource data}}"/>
    </Window>

    public partial class SortXmlDataProblem : Window
    {
        public SortXmlDataProblem()
        {
            InitializeComponent();
            this.cb1.Loaded += delegate
            {
                CollectionViewSource cvs = this.TryFindResource("data") as CollectionViewSource;
                if (cvs != null)
                {
                    ListCollectionView view = cvs.View as ListCollectionView;
                    if (view != null)
                    {
                        view.CustomSort = new XmlComparer();
                    }
                }
            };
        }

        public class XmlComparer : IComparer
        {
            public Int32 Compare(Object x, Object y)
            {
                XmlElement a = x as XmlElement;
                XmlElement b = y as XmlElement;
                if (a != null && b != null)
                {
                    return String.Compare(a.InnerText, b.InnerText);
                }

                return -1;
            }
        }
    }


    Hope this helps
    Thursday, March 20, 2008 4:25 AM
  • Thanks Dan and Marco for the helpful posts. Appreciate them very much Smile.

    The code helps alot. Smile

    There's also another method that I've tried which gives me the correct sorting result.

    I wrote a function called SortData() and called it everytime I add a new node to the xml document.

    //This method is called anytime I want to add a new node.
    private void AddXmlNode()
    {
    //This will add a xml node (with the CData tag) to the current xml document
    AddNode();

    //Call SortData to sort the comboBox
    SortData();
    }



    private
    void SortData()

    {

    //This will clear the CData tag from the node that I've just added

    ClearTag();      


         cb1.Items.SortDescriptions.Clear();

         cb1.Items.SortDescriptions.Add(sd);

    }


    It works but I am not sure if it is good enough and if there's any disadvantage of using this method?


    Best Regards.



     







     
    Saturday, March 22, 2008 2:33 AM
  • using SortDescriptions or CustomSort can both solve the problem, but one little difference you need to pay attention is that SortDescriptions will use the default XmlNodeComparer which only understand XPath property path, if you need to data bind to the CLR property of the data collection discerned XmlNode, and you need to sort the data based on this CLR property, you need to resort to CustomSort instead, in my example, InnerText is a CLR property, which not recognized by XPath, so you need to use CustomSort instead.

    Hope this helps
    Monday, March 24, 2008 5:29 AM
  • Yes. It's clearer now. Thanks !!

     

    Best Regards.

    Tuesday, March 25, 2008 12:01 PM
  • Hi,

    Is there is also any way to apply CustomSort for multi columns?

    e.g.

    ListCollectionView view = cvs.View as ListCollectionView;
    foreach(SortingInfo sortInfo in SortingInfos)
    {
    if (view != null)
        {
           view.CustomSort = new XmlComparer();
        }

    }

    public class XmlComparer : IComparer
        {
            public Int32 Compare(Object x, Object y)
            {
                XmlElement a = x as XmlElement;
                XmlElement b = y as XmlElement;
                if (a != null && b != null)
                {
                    return String.Compare(a.InnerText, b.InnerText);
                }

                return -1;
            }
        }


    In my case it is always getting last Column Sorting rather than sorting with every criteria, am I missing

    something here?



    Engr.Saime Aley
    Tuesday, October 28, 2008 4:59 PM
  •  <Window.Resources> 
           
    <CollectionViewSource Source="{Binding Path=CandyNames}" x:Key="cvs"> 
               
    <CollectionViewSource.SortDescriptions> 
                   
    <scm:SortDescription /> 
               
    </CollectionViewSource.SortDescriptions> 
           
    </CollectionViewSource> 
     
       
    </Window.Resources> 
       
    <StackPanel> 
           
    <ComboBox ItemsSource="{Binding Source={StaticResource cvs}}" /> 
           
    <Button Content="Add" Click="OnAdd" /> 
       
    </StackPanel>
    Thursday, June 10, 2010 7:11 AM