TalkingCode
TalkingCode

Reputation: 13557

WPf ListView : Save reorderd column order

For a WPF project in need to save the width and the column order of a ListView because these are things the user can change. I guess it is no problem getting the current width but the current position seems to be a bit difficult.

In WinForms there was something like index and displayIndex but I don't see it in WPF. How is it done?

BTW : Serializing the whole control is not an option.

Edit:

I found some samples using the listView.columns property. But I don't have such a property in my listView

My XAML code is like this:

<ListView>
    <ListView.View>
        <GridView>
            <GridViewColumn>
            ....

Upvotes: 5

Views: 4333

Answers (2)

Dennis Kuypers
Dennis Kuypers

Reputation: 556

The Columns are always in the same oder that the gridView.Columns Collection is. You can hook into the gridView.CollectionChanged event to react to changes, see also WPF Listview : Column reorder event?

I am using a Behavior to do this. There is a dependency property on the Behavior that is bound to my DataContext. You need a reference to System.Windows.Interactivityto use interactivity.

On my DataContext there is an ObservableCollection of ColumnInfo that I store in my configuration on application exit:

public class ColumnInfo
    {
        public string HeaderName { get; set; }
        public int Width { get; set; }
        public int Index { get; set; }
    }

In your control add the namespace

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

And the ListView is something like

<ListView ItemsSource="{Binding SomeCollection}">
    <ListView.View>
        <GridView>
            <i:Interaction.Behaviors>
                <b:GridViewColumnBehavior Columns="{Binding Columns}" />
            </i:Interaction.Behaviors>
        </GridView>
    </ListView.View>
</ListView>

The Behavior I'm using (parts of it)

public class GridViewColumnBehavior : Behavior<GridView>
{
    public ObservableCollection<ColumnInfo> Columns
    {
        get { return (ObservableCollection<ColumnInfo>)GetValue(ColumnsProperty); }
        set { SetValue(ColumnsProperty, value); }
    }

    public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register("Columns", typeof(ObservableCollection<ColumnInfo>), typeof(GridViewColumnBehavior), new PropertyMetadata(null, new PropertyChangedCallback(Columns_Changed)));

    private static void Columns_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var b = d as GridViewColumnBehavior;
        if (b == null) return;

        b.SetupColumns(e.NewValue as ObservableCollection<Column>);
    }

    public void SetupColumns(ObservableCollection<Column> oldColumns)
    {
        if(oldColumns != null)
        {
            oldColumns.CollectionChanged -= Columns_CollectionChanged;
        }

        if ((Columns?.Count ?? 0) == 0) return;

        AssociatedObject.Columns.Clear();

        foreach (var column in Columns.OrderBy(c => c.Index))
        {
            AddColumn(column);
        }

        Columns.CollectionChanged += Columns_CollectionChanged;
    }

    private void Columns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        var lookup = AssociatedObject.Columns.Select((c, i) => new { Index = i, Element = c.Header.ToString() }).ToLookup(ci => ci.Element, ci => ci.Index);
        foreach (var c in Columns)
        {
            // store the index in the Model (ColumnInfo)
            c.Index = lookup[c.HeaderName].FirstOrDefault();
        }
    }
}

Enjoy!

Upvotes: 1

Teodor
Teodor

Reputation: 497

I managed to do that using the Move(…) method of the GridView's Columns collection

If you have the new order stored somehow, you could try:

((GridView)myListView.View).Columns.Move(originalIndex, newIndex);

Edit: This is NOT XAML, but code you should put in the .xaml.cs file

Upvotes: 5

Related Questions