Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
359 views
in Technique[技术] by (71.8m points)

c# - How to resize a certain control based on Window size in WPF?

I have a ListView control where I want to resize the last column in sync with the size of the Window. So if the Window's width increases by 100 units, I want the columns' width to also increase by 100.

Should I be using the Resize event on the Window and use a magic number to resize the column header manually, sort of like?:

columnHeader.Width = windowSize.X - 400;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a solution that uses databinding and some converter magic to get the job done.

First, let's describe a simple ListView with some data and 3 columns.

<ListView>
    <ListView.View>
        <GridView>
            <GridViewColumn Width="140" Header="Date" />
            <GridViewColumn Width="140" Header="Day" 
                            DisplayMemberBinding="{Binding DayOfWeek}" />
            <GridViewColumn Width="140" Header="Year" 
                            DisplayMemberBinding="{Binding Year}"/>
        </GridView>
    </ListView.View>

    <sys:DateTime>1/2/3</sys:DateTime>
    <sys:DateTime>4/5/6</sys:DateTime>
    <sys:DateTime>7/8/9</sys:DateTime>
</ListView>

This will get us to where you are. Now, in order to have the last column grow and shrink based on the parents width, we need to do build a converter and hook it up. First, let's adjust the last column of the GridView to make the width dynamic.

<GridViewColumn Header="Year" DisplayMemberBinding="{Binding Year}">
    <GridViewColumn.Width>
        <MultiBinding Converter="{StaticResource lastColumnMaximizerConverter}">
            <Binding Path="ActualWidth" 
                     RelativeSource="{RelativeSource AncestorType=ListView}"/>
            <Binding Path="View.Columns" 
                     RelativeSource="{RelativeSource AncestorType=ListView}"/>
        </MultiBinding>
    </GridViewColumn.Width>
</GridViewColumn>

What we've done here is created a MultiBinding object, hooked up an IMultiValueConverter, and described several parameters that we want to send into the IMultiValueConverter implementation. The first parameter is the ActualWidth of the parent ListView. The second parameter is the View.Columns collection on the parent ListView. We now have everything we need to calculate the final width of the last column in our view.

Now we need to create an IMultiValueConverter implementation. I happen to have one right here.

public class WidthCalculationMultiConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, 
                          object parameter, CultureInfo culture)
    {
        // do some sort of calculation
        double totalWindowWidth;
        double otherColumnsTotalWidth = 0;
        double.TryParse(values[0].ToString(), out totalWindowWidth);
        var arrayOfColumns = values[1] as IList<GridViewColumn>;

        for (int i = 0; i < arrayOfColumns.Count - 1; i++)
        {
            otherColumnsTotalWidth += arrayOfColumns[i].Width;
        }

        return (totalWindowWidth - otherColumnsTotalWidth) < 0 ? 
                     0 : (totalWindowWidth - otherColumnsTotalWidth);
    }

    public object[] ConvertBack(object value, Type[] targetTypes,
                                object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Psst.. by the way, this is not the safest code. You'll want to spruce it up! It's just a demo and you know how demo code is! :)

Last of all, we need to instantiate our Converter instance in our XAML.

<Grid.Resources>
    <Converters:WidthCalculationMultiConverter 
                  x:Key="lastColumnMaximizerConverter"/>
</Grid.Resources>

So now we have a a converter that will figure out how wide we want to make the last column, based on the widths of the columns (not including the last one) in the ListView and a binding that will use that converter and send in the required parameters and get the "right answer" out and apply it to the last column's width.

If you've put this together right, you should now have a ListView in which the last column will always stretch to the maximum width of the parent ListView.

I hope that this gets you going but also helped you understand how we can do this without writing some code-behind and using more of the facilities provided by WPF.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...