如何根据WPF中的窗口大小调整某个控件的大小?

时间:2011-04-06 21:26:26

标签: c# .net wpf layout

我有一个ListView控件,我希望调整最后一列的大小,与Window的大小同步。因此,如果Window的宽度增加100个单位,我希望列的宽度也增加100个。

我是否应该在窗口上使用Resize事件并使用幻数来手动调整列标题的大小,有点像?:

columnHeader.Width = windowSize.X - 400;

2 个答案:

答案 0 :(得分:7)

这是一个使用数据绑定和一些转换器魔术来完成工作的解决方案。

首先,让我们描述一个带有一些数据和3列的简单ListView。

<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>

这将使我们到达你所在的位置。现在,为了让最后一列根据父级宽度增长和缩小,我们需要构建一个转换器并将其连接起来。首先,让我们调整GridView的最后一列以使宽度动态化。

<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>

我们在这里做的是创建一个MultiBinding对象,连接IMultiValueConverter,并描述了我们想要发送到IMultiValueConverter实现的几个参数。第一个参数是父ListView的ActualWidth。第二个参数是父ListView上的View.Columns集合。我们现在拥有了计算视图中最后一列最终宽度所需的一切。

现在我们需要创建一个IMultiValueConverter实现。我碰巧在这里有一个。

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 ..顺便说一下,这不是最安全的代码。你会想要修饰它!这只是一个演示,你知道演示代码是如何的! :)

最后,我们需要在XAML中实例化我们的Converter实例。

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

所以现在我们有一个转换器,根据ListView中列(不包括最后一列)的宽度以及将使用该转换器并发送的绑定,确定我们想要制作最后一列的宽度在所需参数中并获得“正确答案”并将其应用于最后一列的宽度。

如果你把它放在一起,你现在应该有一个ListView,其中最后一列将始终延伸到父ListView的最大宽度。

我希望这能让你前进但也帮助你理解我们如何在不编写代码隐藏和使用WPF提供的更多功能的情况下实现这一目标。

答案 1 :(得分:1)

我不能完全赞同这个答案,因为我得到了here

但基本上这就是这个想法:

使用GridView替换listView中的“View”。然后,您可以为第一列指定所需的宽度。在这种情况下100,50,50。 然后我们在最后一列添加一个绑定,它将父ListView控件作为输入。但我们允许转换器为我们做肮脏的工作。

<ListView>
    <ListView.View>
      <GridView>
        <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="100"/>
        <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="50"/>
        <GridViewColumn Header="Title" DisplayMemberBinding="{Binding}" Width="50"/>
        <GridViewColumn Header="4" DisplayMemberBinding="{Binding}">
        <GridViewColumn.Width>
          <MultiBinding Converter="{StaticResource starWidthConverter}">
            <Binding Path="ActualWidth"  RelativeSource="{RelativeSource AncestorType=ListView}"/>
            <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListView}"/>
          </MultiBinding>
        </GridViewColumn.Width>
      </GridViewColumn>
     </GridView>
    </ListView.View>
    <ListViewItem>item1</ListViewItem>
    <ListViewItem>item2</ListViewItem>
    <ListViewItem>item3</ListViewItem>
    <ListViewItem>item4</ListViewItem>
  </ListView>

因此,在转换器'转换'功能中,我们这样做:

ListView listview = value[1] as ListView;
double width = listview.ActualWidth;
GridView gv = listview.View as GridView;
for(int i = 0;i < gv.Columns.Count-1;i++)
{
  if(!Double.IsNaN(gv.Columns[i].Width))
    width -= gv.Columns[i].Width;
}
return width - 5;// this is to take care of margin/padding

它抓取listview宽度,并计算新的大小。