Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF View ListView Backwards

Tags:

c#

listview

wpf

I want to be able to maintain a list in the background that puts new items at the end of the list (to avoid Insert() pushing the items around on updates) but to be able to display it in the reverse order without "sorting".

I just want it to show up in the list view in the reverse order that it is in the list. Can I do this with a template or something similar?

like image 357
Paul Avatar asked Aug 19 '11 15:08

Paul


2 Answers

You can change the ListView's ItemsPanel to be a DockPanel with LastChildFill set to false. Then in the ItemContainerStyle, set the DockPanel.Dock property to bottom. This will start filling at the bottom and work its way up to the top. I put the ListView in a grid with 2 rows, first's Height="Auto" and second's Height="*" and it acted just like a normal ListView, but with the items reversed.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <ListBox Grid.Row="0">
    <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}"
                   BasedOn="{StaticResource {x:Type ListBoxItem}}">
                <Setter Property="DockPanel.Dock"
                        Value="Bottom" />
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <DockPanel LastChildFill="False" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>

Idea taken from: https://stackoverflow.com/a/493059/2812277

like image 190
Ryan West Avatar answered Oct 13 '22 01:10

Ryan West


Update
Here is an Attached Behavior which will reverse any ItemsControl. Use it like this

<ListBox behaviors:ReverseItemsControlBehavior.ReverseItemsControl="True"
         ...>

ReverseItemsControlBehavior

public class ReverseItemsControlBehavior
{
    public static DependencyProperty ReverseItemsControlProperty =
        DependencyProperty.RegisterAttached("ReverseItemsControl",
                                            typeof(bool),
                                            typeof(ReverseItemsControlBehavior),
                                            new FrameworkPropertyMetadata(false, OnReverseItemsControlChanged));
    public static bool GetReverseItemsControl(DependencyObject obj)
    {
        return (bool)obj.GetValue(ReverseItemsControlProperty);
    }
    public static void SetReverseItemsControl(DependencyObject obj, object value)
    {
        obj.SetValue(ReverseItemsControlProperty, value);
    }

    private static void OnReverseItemsControlChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue == true)
        {
            ItemsControl itemsControl = sender as ItemsControl;
            if (itemsControl.IsLoaded == true)
            {
                DoReverseItemsControl(itemsControl);
            }
            else
            {
                RoutedEventHandler loadedEventHandler = null;
                loadedEventHandler = (object sender2, RoutedEventArgs e2) =>
                {
                    itemsControl.Loaded -= loadedEventHandler;
                    DoReverseItemsControl(itemsControl);
                };
                itemsControl.Loaded += loadedEventHandler;
            }
        }
    }
    private static void DoReverseItemsControl(ItemsControl itemsControl)
    {
        Panel itemPanel = GetItemsPanel(itemsControl);
        itemPanel.LayoutTransform = new ScaleTransform(1, -1);
        Style itemContainerStyle;
        if (itemsControl.ItemContainerStyle == null)
        {
            itemContainerStyle = new Style();
        }
        else
        {
            itemContainerStyle = CopyStyle(itemsControl.ItemContainerStyle);
        }
        Setter setter = new Setter();
        setter.Property = ItemsControl.LayoutTransformProperty;
        setter.Value = new ScaleTransform(1, -1);
        itemContainerStyle.Setters.Add(setter);
        itemsControl.ItemContainerStyle = itemContainerStyle;
    }
    private static Panel GetItemsPanel(ItemsControl itemsControl)
    {
        ItemsPresenter itemsPresenter = GetVisualChild<ItemsPresenter>(itemsControl);
        if (itemsPresenter == null)
            return null;
        return GetVisualChild<Panel>(itemsControl);
    }
    private static Style CopyStyle(Style style)
    {
        Style styleCopy = new Style();
        foreach (SetterBase currentSetter in style.Setters)
        {
            styleCopy.Setters.Add(currentSetter);
        }
        foreach (TriggerBase currentTrigger in style.Triggers)
        {
            styleCopy.Triggers.Add(currentTrigger);
        }
        return styleCopy;
    }

    private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
    {
        T child = default(T);

        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }
}

Otherwise, you can follow what's outlined in the following link: WPF reverse ListView

<ListBox ...>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel VerticalAlignment="Top"  Orientation="Vertical">
                <VirtualizingStackPanel.LayoutTransform>
                    <ScaleTransform ScaleX="1" ScaleY="-1" />
                </VirtualizingStackPanel.LayoutTransform>
            </VirtualizingStackPanel>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="LayoutTransform">
                <Setter.Value>
                    <ScaleTransform ScaleX="1" ScaleY="-1" />
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>
like image 41
Fredrik Hedblad Avatar answered Oct 13 '22 01:10

Fredrik Hedblad