WPF Sorting ItemsControl under DataTemplate

2019-08-10 02:30发布

问题:

I am using ItemsControl under DataTemplate. I want to sort ItemsControl ic using id column.

   <DataTemplate x:Key="With">
        <DockPanel>               
            <StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
                <TextBlock Text="{Binding Path=fil}" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
                <mui:ModernButton  IconData="{StaticResource PlayIconData}" Click="FullPlayback" Margin="0,0,6,8" ></mui:ModernButton>
            </StackPanel>
            <StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
                <TextBlock Text="{Binding Path=e1}" Foreground="Red" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
                <TextBlock Text="{Binding Path=m1}" Foreground="LightSalmon" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
                <TextBlock Text="{Binding Path=n1}" Foreground="Orange" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
                <TextBlock Text="{Binding Path=m2}" Foreground="LightGreen" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
                <TextBlock Text="{Binding Path=m3}" Foreground="Green" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
                <TextBlock Text="{Binding ElementName=H1, Path=Items.Count,Mode=OneWay}" Style="{StaticResource Fixed}" Margin="0,0,6,8" />
            </StackPanel>

            <ItemsControl Name="ic" DockPanel.Dock="Bottom" ItemsSource="{Binding Path=seg}" ItemsPanel="{StaticResource HSPanel}">              
                    <ControlTemplate TargetType="ItemsControl"> 
                        <Border>
                            <ScrollViewer VerticalScrollBarVisibility="Auto">
                                <ItemsPresenter />
                            </ScrollViewer>
                        </Border>
                    </ControlTemplate>
                </ItemsControl.Template>
            </ItemsControl>
        </DockPanel>
    </DataTemplate>

i tried below options but sorting is not working.

1.Tried sorting in constructor of the user control like following (code behind)

ic.Items.SortDescriptions.Clear();
ic.Items.SortDescriptions.Add(new SortDescription("id", ListSortDirection.Ascending));
ic.Items.Refresh();

But i am unable to access ic in code behind. Errors says "ic does not exists in current context"

2.Tried CollectionViewSource under ItemsControl in xaml which is also not working.

<ItemsControl x:Name="ic" DockPanel.Dock="Bottom" ItemsSource="{Binding Path=segments}" ItemsPanel="{StaticResource HSPanel}">
             <ItemsControl.Resources>
                            <CollectionViewSource x:Key="segments"  Source="{Binding seg}">
                                <CollectionViewSource.SortDescriptions>
                                    <scm:SortDescription PropertyName="id" Direction="Ascending"/>
                                </CollectionViewSource.SortDescriptions>
                            </CollectionViewSource>
                        </ItemsControl.Resources>
                <ItemsControl.Template>

3.Tried CollectionViewSource under ControlTemplate in xaml which is also not working.

                    <ControlTemplate TargetType="ItemsControl">                            
                            <ControlTemplate.Resources>
                                <CollectionViewSource x:Key="segments" Source="{Binding seg}" >
                                    <CollectionViewSource.SortDescriptions>
                                        <scm:SortDescription PropertyName="sortId" Direction="Ascending"/>
                                    </CollectionViewSource.SortDescriptions>
                                </CollectionViewSource>
                        </ControlTemplate.Resources>

But i initialised Loaded event of ic and tried to do sorting from there.In this case initially when the page loads, the items are not sorted. But when i move to another user control and come back to this current user control, the items looks sorted out perfectly.

    private void ic_Loaded(object sender, RoutedEventArgs e)
    {
        ItemsControl ic = (ItemsControl)sender;
        ic.Items.SortDescriptions.Clear();
        ic.Items.SortDescriptions.Add(new SortDescription("id", ListSortDirection.Ascending));
        ic.Items.Refresh();
    }

回答1:

You have two options :

1 - Sort your source collection (seg) in View Model.

2 - Use CollectionViewSource (http://msdn.microsoft.com/fr-fr/library/system.windows.data.collectionviewsource.aspx). Here is a full working exemple:

I have added this code in to an empty WPF window:

public class SomeVM
{
    public ObservableCollection<SomeItemVM> Items { get; set; }

    public SomeVM()
    {
        Items = new ObservableCollection<SomeItemVM>();
    }
}

public class SomeItemVM
{
    public string id { get; set; }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        //Create some VM
        SomeVM data = new SomeVM();
        data.Items.Add(new SomeItemVM() { id = "3" });
        data.Items.Add(new SomeItemVM() { id = "4" });
        data.Items.Add(new SomeItemVM() { id = "1" });
        data.Items.Add(new SomeItemVM() { id = "2" });

        this.DataContext = data;
    }

}

Then in XAML I add a content control that will hold the VM and a DataTemplate that will describe the way the VM will be displayed:

<Window.Resources>

    <DataTemplate x:Key="With">
        <DockPanel>
            <DockPanel.Resources>
                <!-- CollectionViewSource should be declared as a resource of parent container of the ItemsControl. 
                     Otherwise there will be an exception of StaticResourceHolder --> 
                <CollectionViewSource x:Key="segments" Source="{Binding Items}">
                    <CollectionViewSource.SortDescriptions>
                        <scm:SortDescription PropertyName="id" Direction="Ascending"/>
                    </CollectionViewSource.SortDescriptions>
                </CollectionViewSource>
            </DockPanel.Resources>

            <ItemsControl Name="ic" DockPanel.Dock="Bottom" ItemsSource="{Binding Source={StaticResource segments}}">

                <ItemsControl.Template>
                    <ControlTemplate TargetType="ItemsControl">
                        <Border>
                            <ScrollViewer VerticalScrollBarVisibility="Auto">
                                <ItemsPresenter />
                            </ScrollViewer>
                        </Border>
                    </ControlTemplate>
                </ItemsControl.Template>

                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding id}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DockPanel>
    </DataTemplate>

</Window.Resources>

<Grid>

    <ContentControl Content="{Binding}" ContentTemplate="{StaticResource With}"/>

</Grid>

The resulting ItemsControl will display sorted items.



回答2:

Finally i solved the sorting problem. I am binding segments(observablecollection< seg>) to the itemscontrol. Previously In code behind i was generating segments directly like below

segments[0].name="GHI";
segments[0].age=40;
segments[1].name="ABC";
segments[1].age=20;
segments[2].name="DEF";
segments[2].age=30;

Instead of generating segments directly, i created another variable objSegments and generated the values like below.

objSegments[0].name="GHI";
objSegments[0].age=40;
objSegments[1].name="ABC";
objSegments[1].age=20;
objSegments[2].name="DEF";
objSegments[2].age=30;

After generating all the values, sorting is done and assigned to segments using the code below.

        ObservableCollection<seg> sortedSegments = new ObservableCollection<seg>(objSegments.OrderBy(c => c.id));
        foreach (var objSeg in sortedSegments)
        {
            segments.Add(objSeg);
        }

It worked fine for me.



标签: wpf wpf-4.0