如何在控件模板中为WPF中的ListView列应用MinWidth?

时间:2012-04-10 22:50:44

标签: wpf xaml listview controltemplate gridviewcolumn

在回答类似问题here之后,我能够在XAML页面上设置MinWidth。

我想要做的是在所有ListView的所有GridViewColumn的控件模板中完成此操作。

这可能吗?

更新

我在下面尝试了一些简单的示例代码,但它不起作用:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <Style TargetType="{x:Type GridViewColumnHeader}" >
            <Setter Property="MinWidth" Value="200" />
        </Style>
    </Window.Resources>

    <Grid Width="500">
        <Border BorderBrush="Black" BorderThickness="2" Margin="20">
            <ListView SelectionMode="Single">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Header 1" Width="Auto">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock Text="Hello There"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Header 2" Width="Auto" />
                    </GridView>
                </ListView.View>
            </ListView>
        </Border>
    </Grid>
</Window>

7 个答案:

答案 0 :(得分:5)

<Window.Resources>
    <Style TargetType="{x:Type GridViewColumnHeader}" >
        <Setter Property="MinWidth" Value="400" />
    </Style>
</Window.Resources>

答案 1 :(得分:5)

如果使用GridViewColumnHeader,则可以处理大小更改:

  <GridView>
     <GridViewColumn>
        <GridViewColumnHeader Content="HeaderContent" SizeChanged="HandleColumnHeaderSizeChanged"/> 
   ...
代码中的

    private void HandleColumnHeaderSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
    {
        if (sizeChangedEventArgs.NewSize.Width <= 60) {
            sizeChangedEventArgs.Handled = true;
            ((GridViewColumnHeader) sender).Column.Width = 60;
        }
    }

答案 2 :(得分:4)

 <ListView>
        <ListView.View>
            <GridView>
                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock MinWidth="100"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                 ...more columns...
            </GridView>
        </ListView.View>
    </ListView>

答案 3 :(得分:4)

我也偶然发现了这个。要解决这个问题,我必须做两件事:

  1. 修改ListView标题的ControlTemplate。
  2. 在ControlTemplate中处理Thumb的DragDelta事件。
  3. ListView的标题是GridViewColumnHeader。 下面显示的是GridViewColumnHeader的ControlTemplate的简化版本。我们可以看到,它在Canvas中使用Thumb来创建拖动/调整大小效果。

    PS:要获得完整的GridViewColumnHeader ControlTemplate,请参阅How to grab WPF 4.0 control default templates?

    <ControlTemplate TargetType="GridViewColumnHeader">
    <Grid SnapsToDevicePixels="True">
        <Border BorderThickness="0,1,0,1" Name="HeaderBorder" ...>
        <!-- omitted -->
        </Border>
        <Border BorderThickness="1,0,1,1" Name="HeaderHoverBorder" Margin="1,1,0,0" />
        <Border BorderThickness="1,1,1,0" Name="HeaderPressBorder" Margin="1,0,0,1" />
        <Canvas>
            <Thumb Name="PART_HeaderGripper">
            <!-- omitted -->
            </Thumb>
        </Canvas>
    </Grid>
    <ControlTemplate.Triggers>
    <!-- omitted -->
    </ControlTemplate.Triggers>
    

    因此,为了限制GridViewColumnHeader的大小,我们需要挂钩Thumb的拖动事件(DragStarted,DragDelta,DragCompleted ......等)。

    只要我们知道DragDelta内的MinSize,我们所需要的就是DragDeltaEventHandler事件。

    下面显示的是带有注释的XAML修改。

    <Grid Width="500">
        <Border BorderBrush="Black" BorderThickness="2" Margin="20">
            <ListView SelectionMode="Single">
                <ListView.View>
                    <GridView>                        
                        <GridViewColumn Header="Header 1" Width="Auto">
                            <!-- Apply a style targeting GridViewColumnHeader with MinWidth = 80 and a ControlTemplate -->
                            <GridViewColumn.HeaderContainerStyle>
                                <Style TargetType="{x:Type GridViewColumnHeader}">
                                    <Setter Property="MinWidth" Value="80" />
                                    <Setter Property="Control.Template" Value="{DynamicResource myGridViewColumnHeaderControlTemplate}" />
                                </Style>
                            </GridViewColumn.HeaderContainerStyle>**
                        </GridViewColumn>
                        <GridViewColumn Header="Header 2" Width="Auto" />
                    </GridView>
                </ListView.View>
            </ListView>
        </Border>
    </Grid>
    

    在myGridViewColumnHeaderControlTemplate中添加一些XAML:

    1. 将GridViewColumnHeader的MinWidth绑定到Canvas的MinWidth。
    2. 连接Thumb的DragDelta事件。
    3. <ControlTemplate x:Key="TemplateGridViewColumnHeader" TargetType="GridViewColumnHeader">
          <!-- omitted -->
          <Canvas MinWidth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=MinWidth, Mode=OneTime}">
              <Thumb x:Name="PART_HeaderGripper" DragDelta="myGridViewColumnHeader_DragDelta">
      

      最后是myGridViewColumnHeader_DragDelta函数:

          private void myGridViewColumnHeader_DragDelta(object sender, DragDeltaEventArgs e)
          {
              DependencyObject parent = sender as DependencyObject;
      
              try
              {
                  do
                  {
                      parent = VisualTreeHelper.GetParent(parent as DependencyObject);
                  } while (parent.GetType() != typeof(Canvas));
      
                  Canvas canvas = parent as Canvas;
                  if (canvas.ActualWidth + e.HorizontalChange < canvas.MinWidth)
                  {
                      e.Handled = true;
                  }
              }
              catch
              {
              }
          }
      

      这是我找到工作的唯一方法。希望有一种更简单的方法。

答案 4 :(得分:2)

我想对所有列应用最小宽度,所以我这样写:

  public static class GridViewConstraints
  {
    public static readonly DependencyProperty MinColumnWidthProperty =
        DependencyProperty.RegisterAttached("MinColumnWidth", typeof(double), typeof(GridViewConstraints), new PropertyMetadata(75d, (s,e) =>
        {
            if(s is ListView listView)
            {
                listView.Loaded += (lvs, lve) =>
                {
                    if(listView.View is GridView view)
                    {
                        foreach (var column in view.Columns)
                        {
                            SetMinWidth(listView, column);

                            ((System.ComponentModel.INotifyPropertyChanged)column).PropertyChanged += (cs, ce) =>
                            {
                                if (ce.PropertyName == nameof(GridViewColumn.ActualWidth))
                                    SetMinWidth(listView, column);
                            };
                        }
                    }
                };
            }
        }));

    private static void SetMinWidth(ListView listView, GridViewColumn column)
    {
        double minWidth = (double)listView.GetValue(MinColumnWidthProperty);

        if (column.Width < minWidth)
            column.Width = minWidth;
    }

    public static double GetMinColumnWidth(DependencyObject obj) => (double)obj.GetValue(MinColumnWidthProperty);

    public static void SetMinColumnWidth(DependencyObject obj, double value) => obj.SetValue(MinColumnWidthProperty, value);
}

只需将其放在您的列表视图中:

<ListView b:GridViewConstraints.MinColumnWidth="255" />

答案 5 :(得分:1)

你可以试试这个,对于每一列,如果你想为所有列设置不同的最小宽度和最大为自动

 <ListView.View>
    <GridView >
        <GridViewColumn Header="FILE NAME" DisplayMemberBinding="{Binding fileName}" Width="auto" >
            <GridViewColumn.HeaderContainerStyle>
                <Style TargetType="{x:Type GridViewColumnHeader}">
                    <Setter Property="MinWidth" Value="200" />

                </Style>
            </GridViewColumn.HeaderContainerStyle>
        </GridViewColumn>
                <GridViewColumn Header="ERROR DETAILS" DisplayMemberBinding="{Binding errorMessage}" Width="auto">
            <GridViewColumn.HeaderContainerStyle>
                <Style TargetType="{x:Type GridViewColumnHeader}">
                    <Setter Property="MinWidth" Value="396" />

                </Style>
            </GridViewColumn.HeaderContainerStyle>
        </GridViewColumn>

    </GridView>
</ListView.View>

答案 6 :(得分:0)

更新到Billy Jake O'Connor的解决方案中,该解决方案提供了所有解决方案中最简单,易于实现和正确工作的解决方案。

对于不希望所有列共享相同最小宽度的用户,在下一次代码更新中,您可以为每个列设置特定的最小宽度,分别在列属性中直接指定最小宽度。

public static class GridColumn {
    public static readonly DependencyProperty MinWidthProperty =
        DependencyProperty.RegisterAttached("MinWidth", typeof(double), typeof(GridColumn), new PropertyMetadata(75d, (s, e) => {
            if(s is GridViewColumn gridColumn ) {
                SetMinWidth(gridColumn);
                ((System.ComponentModel.INotifyPropertyChanged)gridColumn).PropertyChanged += (cs, ce) => {
                    if(ce.PropertyName == nameof(GridViewColumn.ActualWidth)) {
                        SetMinWidth(gridColumn);
                    }
                };
            }
        }));

    private static void SetMinWidth(GridViewColumn column) {
        double minWidth = (double)column.GetValue(MinWidthProperty);

        if(column.Width < minWidth)
            column.Width = minWidth;
    }

    public static double GetMinWidth(DependencyObject obj) => (double)obj.GetValue(MinWidthProperty);

    public static void SetMinWidth(DependencyObject obj, double value) => obj.SetValue(MinWidthProperty, value);
}

XAML可能是这样的(“ local”是您使用的名称空间名称,请进行相应修改)

<ListView>
    <ListView.View>
        <GridView>
            <GridViewColumn local:GridColumn.MinWidth="25" />
            <GridViewColumn local:GridColumn.MinWidth="100" />
            <GridViewColumn local:GridColumn.MinWidth="200" />
        </GridView>
    </ListView.View>
</ListView>