WPF ListView autogrow column

254 Views Asked by At

If I create a simple ListView with an auto-grow column, it only auto grows the first "batch" items are added. Why does this happen, and is there any way to fix it?

I've tried both using an ObservableCollection (example shown), and manually adding items to LstItems.Items, same behaviour. The first time you click BtnAdd it auto-grows as expected, subsequent times it does not.

XAML:

    <ListView Margin="12,12,12,41" Name="LstItems">
        <ListView.View>
            <GridView>
                <GridViewColumn Width="100" Header="Row 1" DisplayMemberBinding="{Binding Path=Col1}" />
                <GridViewColumn Width="Auto" Header="Row 2" DisplayMemberBinding="{Binding Path=Col2}" />
            </GridView>
        </ListView.View>
    </ListView>

Code:

public partial class Window1 : Window
{
    private readonly ObservableCollection<MyData> _data = new ObservableCollection<MyData>();

    private const int NumRepeats = 2;
    private const int EnumerationIncrement = 3;

    private int _enumerationCount = 3;

    public Window1()
    {
        InitializeComponent();
        LstItems.ItemsSource = _data;
    }

    private void BtnAdd_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 1; i <= NumRepeats; i++)
        {
            string data = String.Join(", ", Enumerable.Repeat("Test Data", _enumerationCount));
            _data.Add(new MyData { Col1 = "Test", Col2 = data });
            _enumerationCount += EnumerationIncrement;
        }
    }
}
2

There are 2 best solutions below

3
paparazzo On BEST ANSWER

I have seen this behavior also. It only sizes the first screen paint. It would be a lot of overhead to size each paint. And if a user resized a column they probably don't what it changed. Why not just give column 2 the rest of the space? You would do that with a converter.

5
JKennedy On

You datacontext of the listview is to 1 single item (MyData) I'm guessing this is accidental? you should leave the datacontext and bind the itemSource of the Listview to _data instead

XAML

 <ListView Margin="12,12,12,41" Name="LstItems" ItemSource="{Binding _data}">
        <ListView.View>
            <GridView>
                <GridViewColumn Width="100" Header="Row 1" DisplayMemberBinding="{Binding Path=Col1}" />
                <GridViewColumn Width="Auto" Header="Row 2" DisplayMemberBinding="{Binding Path=Col2}" />
            </GridView>
        </ListView.View>
    </ListView>

Code:

public partial class Window1 : Window
{
    public ObservableCollection<MyData> _data = new ObservableCollection<MyData>();

    private const int NumRepeats = 2;
    private const int EnumerationIncrement = 3;

    private int _enumerationCount = 3;

    public Window1()
    {
        InitializeComponent();
    }

    private void BtnAdd_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 1; i <= NumRepeats; i++)
        {
            string data = String.Join(", ", Enumerable.Repeat("Test Data", _enumerationCount));
            _data.Add(new MyData { Col1 = "Test", Col2 = data });
            _enumerationCount += EnumerationIncrement;
        }
    }
}

I also just spotted probably the main reason for your code not working as you expected. You are pushing the LstItems.ItemsSource in the Window1 constructor. you are not binding the ItemSource. So when _data is updated the ItemSource doesn't know about it. Maybe a quick solution for you without learning about DataBinding would be to do:

    private void BtnAdd_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 1; i <= NumRepeats; i++)
        {
            string data = String.Join(", ", Enumerable.Repeat("Test Data", _enumerationCount));
            _data.Add(new MyData { Col1 = "Test", Col2 = data });
            _enumerationCount += EnumerationIncrement;
        }
        LstItems.ItemSource = _data;
    }

Although I would highly recommend learning about databinding if you have some spare time.