1

I am learning to use ListView to list data with multiple columns (i.e. column 1 is filename, column 2 is number of pages, etc.), and encountered several problems:

  1. The code below shows 2 columns, where the column width is specified by <GridViewColumn Width="Auto">. How can I specify the columns to use all available width? I tried to set Width="*" like the one for Grid, but that generates an error.

  2. How to make ListView nonselectable? I saw this post on making ListBox nonselectable, but a similar approach doesn't work for ListView (shown in code).

UPDATE: solved question #2. see code.

  1. Can you show a simple example of a ListView using DataTemplate? I just want to have something like <ListView ItemsSource="{Binding }" ItemTemplate="{StaticResource myTemplate}"/> in the MainWindow, so things stay clean.

(4.ish. i learned the code below from this post. Please let me know if there is a simpler way.)

Thank you!

<ListView HorizontalContentAlignment="Stretch" Grid.Row="0" ItemsSource="{Binding }">

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="Focusable" Value="False"/>   <--- disable selection
        </Style>
    </ListView.ItemContainerStyle>

    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto">
                <GridViewColumnHeader Content="Filename"/>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Filename}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

            <GridViewColumn Width="Auto">
                <GridViewColumnHeader Content="Pages"/>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Pages}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

        </GridView>
    </ListView.View>
<ListView>
Community
  • 1
  • 1
totoro
  • 3,257
  • 5
  • 39
  • 61

1 Answers1

1

I'm not sure if there is any other straight-forward solution (although I'm almost sure there is not any direct way to go). The following solution can be considered as a work-around but it's actually a beautiful one.

You can make the second column (or generally the last column) fill the remaining space by using some Binding to bind the ListView's Columns' Width to the Grid's Columns' Width. Yes we know that only Grid has some features which no other controls have. Here are the detailed steps:

  • Firstly, we need a Grid having the same number of columns with the ListView. The ListView of course should be placed inside this Grid. By using Grid.ColumnSpan we can make the ListView fill the whole Grid.
  • Secondly, bind the Width of all the Grid columns to the ActualWidth of the corresponding ListView columns except the last Column. The last column of the Grid should have Width set to * (fill the remaining space).
  • Lastly, you need some dummy element (such as a Border) put in the last column of the Grid. We need this dummy element to get its ActualWidth, so that we can bind the last ListView column's Width to that ActualWidth. A ColumnDefinition of the Grid also has the property ActualWidth but it is not a dependency property and also it does not have any property changed notifying mechanism (so we cannot use that property).

Now is the working code:

<Grid Grid.Row="0">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="{Binding ActualWidth,ElementName=firstCol}"/>
    <ColumnDefinition Width="*"/>
  </Grid.ColumnDefinitions>
  <!-- the dummy element -->
  <Border Grid.Column="1" Name="dummy" Margin="5"></Border>
  <ListView HorizontalContentAlignment="Stretch" Grid.ColumnSpan="2"
          ItemsSource="{Binding }">

     <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
          <Setter Property="Focusable" Value="False"/>
        </Style>
     </ListView.ItemContainerStyle>

     <ListView.View>
        <GridView>
          <GridViewColumn Width="Auto" x:Name="firstCol">
              <GridViewColumnHeader Content="Filename"/>
              <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <TextBlock Text="{Binding Path=Filename}"/>
                  </DataTemplate>
              </GridViewColumn.CellTemplate>
           </GridViewColumn>

           <GridViewColumn Width="{Binding ActualWidth, ElementName=dummy}">
              <GridViewColumnHeader Content="Pages"/>
              <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <TextBlock Text="{Binding Path=Pages}"/>
                  </DataTemplate>
              </GridViewColumn.CellTemplate>
           </GridViewColumn>

        </GridView>
      </ListView.View>
  <ListView>
</Grid>

Note that your original ListView may be placed in some Grid (you set its Grid.Row="0"). However when using this trick, the ListView should always be placed inside a wrapper Grid and you have to set Grid.Row="0" (although this is set by default) for this wrapper Grid instead. I mean this wrapper Grid will be placed in your original Grid (if any present).

Update: To make it dynamic like as a Grid, you need more dummy elements (we use just 1 dummy Border for the last column in the code above). Each dummy elements will be put in each Grid's column. As I explained, we need this to proxy the ActualWidth of the Grid's column, although ColumnDefinition also has an ActualWidth property but it cannot be used in Binding (does not support any change notification). Here is the code:

<Grid Grid.Row="0">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="2*"/>
  </Grid.ColumnDefinitions>
  <!-- the dummy elements -->
  <Border Grid.Column="0" Name="dummy1" Margin="5"></Border>
  <Border Grid.Column="1" Name="dummy2" Margin="5"></Border>
  <!-- your ListView -->
  <ListView HorizontalContentAlignment="Stretch" Grid.ColumnSpan="2"
          ItemsSource="{Binding }">

     <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
          <Setter Property="Focusable" Value="False"/>
        </Style>
     </ListView.ItemContainerStyle>

     <ListView.View>
        <GridView>
          <GridViewColumn Width="{Binding ActualWidth, ElementName=dummy1}">
              <GridViewColumnHeader Content="Filename"/>
              <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <TextBlock Text="{Binding Path=Filename}"/>
                  </DataTemplate>
              </GridViewColumn.CellTemplate>
           </GridViewColumn>

           <GridViewColumn Width="{Binding ActualWidth, ElementName=dummy2}">
              <GridViewColumnHeader Content="Pages"/>
              <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <TextBlock Text="{Binding Path=Pages}"/>
                  </DataTemplate>
              </GridViewColumn.CellTemplate>
           </GridViewColumn>

        </GridView>
      </ListView.View>
  <ListView>
</Grid>
King King
  • 61,710
  • 16
  • 105
  • 130