Simulate WPF ListView Column Width Set to "*"
One technique for having a column width that grows/shrinks with ListView width
I'm writing a WPF front-end to a new version of my CPAM library, and the application features a number of
ListView
controls. One of the things that the standard ListView DOES NOT do through simple property settings is all the programmer to set a column width of "*" (meaning consume all horizontal width not consumed by columns with a specified width).
In my case, I wanted the left-most column to be automatically sized, because all of the rest of the columns having a size specified. I was looking for a simple way to implement this, and came up with the following. Handle the SizeChanged event for the ListView, and in the event handler method, and implement code that looks something like this:
private void InnerListView_SizeChanged(object sender, SizeChangedEventArgs e) { if (e.WidthChanged) { GridView view = this.InnerListView.View as GridView; Decorator border = VisualTreeHelper.GetChild(this.InnerListView, 0) as Decorator; if (border != null) { ScrollViewer scroller = border.Child as ScrollViewer; if (scroller != null) { ItemsPresenter presenter = scroller.Content as ItemsPresenter; if (presenter != null) { view.Columns[0].Width = presenter.ActualWidth; for (int i = 1; i < view.Columns.Count; i++) { view.Columns[0].Width -= view.Columns[i].ActualWidth; } } } } } }Because a
ListView
could have enough items to cause the vertical scrollbar to be displayed, we have to account for this in a non hard-wired manner. Essentially, you want to find the width of the "client rectangle" (to put it into a Windows API context), which excludes the vertical scrollbar's width. To accomplish this, we need to get to the ItemsPresenter
control inside the ListView
.
In a standard ListView
, the Child
is a Decorator
, and the ScrollViewer
is the Child
of Decorator
. Finally, the ItemsPresenter
is the Content
of the ScrollViewer
, and guess what - ItemsPresenter.ActualWidth
represents the width of your ListView
content NOT INCLUDING the scrollbar's width. Will wonders never cease?
Once you get the width of your client area, you can loop through all of the columns and subtract their width to come up with a hard-wired width for your "*" column.
Notice - I realize there are probably more WPF-conformant techniques to accomplish this goal, but I am more interested in "getting the work done" than in strictly adhering to a programming paradigm. I also don't really care to work in XAML.