4

I'm trying to get gridviewcolumns in a listview to auto-size to content on when the Binding source is updated (an observablecollection on a viewmodel).

The listview populates fine, but not working when I refresh/update the collection. This is the solution I'm trying so far:

XAML:

<ListView x:Name="ListView" ItemsSource="{Binding Collection, NotifyOnSourceUpdated=True}" SourceUpdated="ListView_SourceUpdated">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto" Header="Test" DisplayMemberBinding={Binding Test}" />
        </GridView>
    </ListView.View>
</ListView>

Codebehind:

private void requestsListView_SourceUpdated(object sender, DataTransferEventArgs e)
    {
        GridView gv = requestsListView.View as GridView;
        if (gv != null)
        {
            foreach (var c in gv.Columns)
            {
                if (double.IsNaN(c.Width))
                {
                    c.Width = c.ActualWidth;
                }
                c.Width = double.NaN;
            }
        }
    }

From what I can tell, the SourceUpdated event never fires. I don't know if this is because the datacontext is set to a ViewModel? Not sure how to interact with the ListView from the VM.

Is there a better way to try to do this using the ViewModel? Still new and trying to learn MVVM.

ctd25
  • 730
  • 1
  • 11
  • 22

2 Answers2

4

Here is a working example :

<Window x:Class="ListViewAutoResize.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <ListView x:Name="lv" Background="Beige" ItemsSource="{Binding items}" >
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Column1" DisplayMemberBinding="{Binding}"/>
                <GridViewColumn Header="Column2" DisplayMemberBinding="{Binding}"/>
                <GridViewColumn Header="Column3" DisplayMemberBinding="{Binding}"/>
            </GridView>
        </ListView.View>
    </ListView>
    <Button Content="Add item" Click="btnAddItem_OnClick"/>
 </StackPanel>
</Window>

Here is the codebehind:

public partial class MainWindow : Window
{
    public ObservableCollection<string> items { get; set; } 
    public MainWindow()
    {
        InitializeComponent();

        items = new ObservableCollection<string>();
        items.Add(("item1"));
        items.Add(("item2"));
        items.Add(("item3333"));
        items.Add(("item4"));
        items.Add(("item5"));
        items.CollectionChanged += items_CollectionChanged;
        this.DataContext = this;

    }

    void items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        var view = lv.View as GridView;
        AutoResizeGridViewColumns(view);
    }

    static void AutoResizeGridViewColumns(GridView view)
    {
        if (view == null || view.Columns.Count < 1) return;
        // Simulates column auto sizing
        foreach (var column in view.Columns)
        {
            // Forcing change
            if (double.IsNaN(column.Width))
                column.Width = 1;
            column.Width = double.NaN;
        }
    }

    private void btnAddItem_OnClick(object sender, RoutedEventArgs e)
    {
        items.Add("aaaaaaaaaabbbbbbb");
    }
}

And that's about it.

Before:

enter image description here

After:

enter image description here

Olaru Mircea
  • 2,570
  • 26
  • 49
0

The SourceUpdated event never fires, becouse you never changed a value of property Collection or property Collection is not notified. You set it once in xaml by Binding but a changes of content in the collection doesn't fire event SourceUpdate.

You right use a ObservableCollection that implement interface INotifyCollectionChanged. So you can hook event CollectionChanged on that collection.

Jocelyn
  • 277
  • 4
  • 21
  • Sorry - I guess I meant to imply it, but I can include the code if necessary. I have an ObservableCollection (Collection) on a ViewModel that is the DataContext of the above view. I also have a button tied to a command that repopulates the ObservableCollection (collection) with new data, which is reflected in the ListView without issue. If I should include this code, let me know, but I didn't think it was relevant, since it's standard and working without issue. – ctd25 Aug 22 '13 at 23:12