简体   繁体   English

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

[英]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 .我有一个ListView控件,我想在其中调整与Window大小同步的最后一列的大小。 So if the Window 's width increases by 100 units, I want the columns' width to also increase by 100.因此,如果Window的宽度增加 100 个单位,我希望列的宽度也增加 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?:我应该在窗口上使用Resize事件并使用幻数手动调整列标题的大小,有点像?:

columnHeader.Width = windowSize.X - 400;

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.首先,让我们描述一个包含一些数据和 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>

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.首先,让我们调整 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>

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.我们在这里所做的是创建了一个 MultiBinding 对象,连接了一个IMultiValueConverter ,并描述了我们想要发送到IMultiValueConverter实现的几个参数。 The first parameter is the ActualWidth of the parent ListView.第一个参数是父 ListView 的 ActualWidth。 The second parameter is the View.Columns collection on the parent ListView.第二个参数是父 ListView 上的 View.Columns 集合。 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.现在我们需要创建一个 IMultiValueConverter 实现。 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. Psst..顺便说一句,这不是最安全的代码。 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.最后,我们需要在 XAML 中实例化 Converter 实例。

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

So now we have aa 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.所以现在我们有一个转换器,它会根据 ListView 中列的宽度(不包括最后一列)和一个将使用该转换器并发送所需的绑定来确定我们想要制作的最后一列的宽度参数并得出“正确答案”并将其应用于最后一列的宽度。

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.如果你把它们放在一起,你现在应该有一个 ListView,其中最后一列将始终拉伸到父 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.我希望这能让你继续前进,但也帮助你了解我们如何在不编写一些代码隐藏和使用 WPF 提供的更多工具的情况下做到这一点。

I can't take full credit for this answer, because I got it here我不能完全相信这个答案,因为我在这里得到了它

But basically this is the idea:但基本上这是这个想法:

Replace the "View" in the listView with a GridView.将 listView 中的“View”替换为 GridView。 Then, you can specify whatever width you want for the first columns.然后,您可以为第一列指定所需的任何宽度。 In this case 100, 50, 50. Then we add a binding on the final column, that takes as input the parent ListView control.在本例中为 100、50、50。然后我们在最后一列上添加一个绑定,它将父 ListView 控件作为输入。 But we are allowing a converter to do the dirty work for us.但是我们允许转换器为我们做肮脏的工作。

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

So, in the converter 'Convert' function we do this:因此,在转换器“Convert”函数中,我们执行以下操作:

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

Which grabs the listview width, and calculates the new size.它获取列表视图的宽度,并计算新的大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM