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.