7

Following the answer to a similar question here, I was able to set the MinWidth on the XAML page.

What I would like to do is accomplish this in the control template for all GridViewColumn's in all ListView's.

Is this possible?

Update:

I tried a simple bit of sample code below, but it does not work:

<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>
Community
  • 1
  • 1
Elan
  • 6,084
  • 12
  • 64
  • 84
  • GridViewColumn does not even have a MinWidth property. You can't can't set a Property in a style or control template that does not exists. Please post your XAML for how you set a MinWidth on a GridViewColumn. – paparazzo Apr 11 '12 at 00:20
  • In the link, it demonstrates the use of the Thumb and handling the DragDelta event to accomplish the MinWidth. Is there a way to accomplish this in a control template? – Elan Apr 11 '12 at 00:24

7 Answers7

10

If you use a GridViewColumnHeader you can handle size changes:

  <GridView>
     <GridViewColumn>
        <GridViewColumnHeader Content="HeaderContent" SizeChanged="HandleColumnHeaderSizeChanged"/> 
   ...

in Code:

    private void HandleColumnHeaderSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
    {
        if (sizeChangedEventArgs.NewSize.Width <= 60) {
            sizeChangedEventArgs.Handled = true;
            ((GridViewColumnHeader) sender).Column.Width = 60;
        }
    }
troYman
  • 1,648
  • 16
  • 18
4
 <ListView>
        <ListView.View>
            <GridView>
                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock MinWidth="100"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                 ...more columns...
            </GridView>
        </ListView.View>
    </ListView>
denis morozov
  • 6,236
  • 3
  • 30
  • 45
  • 1
    I was actually looking for such a solution. It works great when you need to apply it to a specific column. I only had to add the binding on the textblock. – Apostrofix Nov 24 '15 at 19:21
4
<Window.Resources>
    <Style TargetType="{x:Type GridViewColumnHeader}" >
        <Setter Property="MinWidth" Value="400" />
    </Style>
</Window.Resources>
paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • I tried this, but did not work. Didn't you say that GridViewColumn does not have a MinWidth? – Elan Apr 11 '12 at 00:38
  • Read - GridViewColumnHeader - not GridViewColumn. I tested this - it works. – paparazzo Apr 11 '12 at 00:51
  • 1
    I posted a sample, which is not working for me. Could you please see if there is something else you may be doing that I do not have? – Elan Apr 11 '12 at 01:13
  • Please try taking width = auto off the individual columns. I really did test this and it worked in my GridView. – paparazzo Apr 11 '12 at 01:17
  • Same result, dragging/sizing the column bar goes crazy, not smooth, jumps around and does not hold the MinWidth. If it is working for you something must be different. Could you try running my example? – Elan Apr 11 '12 at 01:28
  • Dude I tested YOUR code and it does apply a minimum. Yes bad stuff happens when you re-size but you have Grid width of 400 and with the margin there is not room for two 200. Even without a min the "Hello There" does not show up as you are not really binding. I answered and fixed the stated question. – paparazzo Apr 11 '12 at 01:34
  • 3
    You have a point on the 400 width, oversight on my end. But, regardless it is still not working for me. You don't need to get uptight about it. I would accept the answer if it worked also for me. Unfortunately, the code sample is not working on my end and I am still seeking to resolve this. – Elan Apr 11 '12 at 13:49
  • Doesn't work for me, tried placing it in my Stylesheet, in my Window, in the actual control - nothing... – Maverick Meerkat Apr 30 '18 at 09:27
  • I can only agree with @Elan - the columns appear to initialize correctly with minWidth, but then go completely nuts when resizing. This is not the solution. – Ola Berntsson Nov 11 '18 at 12:54
4

I stumbled into this one also. To solved it I had to do two things :

  1. Modify the ControlTemplate of ListView's header.
  2. Handle the DragDelta event of the Thumb inside the ControlTemplate.

ListView's header is GridViewColumnHeader. Shown below is a simplified version of GridViewColumnHeader's ControlTemplate. As we can see, it uses a Thumb in a Canvas to create the drag/resize effect.

PS: To obtain the complete GridViewColumnHeader ControlTemplate please refer to 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>

So In order to limit the size of GridViewColumnHeader, we need to hook Thumb's drag events(DragStarted, DragDelta, DragCompleted...etc).

Turned out all we need is the DragDelta event as long we can know the MinSize within the DragDeltaEventHandler.

Shown below is modified XAML with comment.

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

In the myGridViewColumnHeaderControlTemplate add some XAML to:

  1. Bind GridViewColumnHeader's MinWidth to Canvas's MinWidth.
  2. Hook up Thumb's DragDelta event.
<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">

Finally the myGridViewColumnHeader_DragDelta function:

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

This is the only way i find working. Do hope there is a simpler way.

Community
  • 1
  • 1
Peter
  • 1,048
  • 10
  • 23
3

Update to the solution of Billy Jake O'Connor who gave the most simple, easy to implement and WORKING CORRECTLY solution of them all.

For the people who don't want all columns to share the same minimum width, with the next code update you can set specific minimum width for each column separately specifying the min width directly in the column properties.

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);
}

And the XAML could be something like this ("local" is your using namespace name, modify accordingly)

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

I wanted to apply a minwidth to all columns, so I wrote this:

  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);
}

Just drop it on your listview:

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

You can try this, for each column, if you want to set different minimum width for all columns and maximum to auto

 <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>
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Priya Rani
  • 17
  • 1
  • 6