Search code examples
wpflistviewbindingtabindex

Column tab order's not changing when dragging columns in ListView


Is it possible to bind a control's TabIndex to the column's order in a GridView? Say, we have a GridView with AllowsColumnReorder set to true, and when we dragging a second column to be last, the tab navigation order would remain column-ordered: 1 -> 3 -> 2, and not the 1-> 2 -> 3 as usually. What i want to do is the tab navigation according to real column layout as on second image. before moving column after moving column

My code for kxaml:

   <Page
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <Grid>
      <ListView ItemsSource="2"
                Grid.Row="1">
                <ListView.View>
                    <GridView AllowsColumnReorder="True">
                        <GridViewColumn Header="One">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Width="100" Text="1"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Two">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Width="100" Text="2"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Three">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Width="100" Text="3"/>                             
                               </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
      </Grid>
    </Page>

Solution

  • here is an example with datagrid instead

    <DataGrid ItemsSource="2" Grid.Row="1">
      <DataGrid.CellStyle>
        <Style TargetType="{x:Type DataGridCell}">
          <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
        </Style>
      </DataGrid.CellStyle>
      <DataGrid.Columns>
        <DataGridTemplateColumn Header="One">
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <TextBox Width="100" Text="1" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Two">
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <TextBox Width="100" Text="2" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Three">
          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <TextBox Width="100" Text="3" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
      </DataGrid.Columns>
    </DataGrid>
    

    EDIT

    here is a solution with listview that works, but i think its not the best...

    public class CustomGridViewColumn : GridViewColumn
    {
      public static readonly DependencyProperty ColumnIndexProperty =
        DependencyProperty.Register("ColumnIndex", typeof(int), typeof(CustomGridViewColumn),
                                    new FrameworkPropertyMetadata());
    
      public int ColumnIndex {
        get { return (int)GetValue(ColumnIndexProperty); }
        set { SetValue(ColumnIndexProperty, value); }
      }
    }
    
    public partial class Window1 : Window
    {
      public Window1()
      {
        InitializeComponent();
        gridView.Columns.CollectionChanged+= new NotifyCollectionChangedEventHandler(gridView_Columns_CollectionChanged);
      }
    
      void gridView_Columns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
      {
        var index = 0;
        foreach(CustomGridViewColumn col in gridView.Columns){
          col.ColumnIndex=index++;
        }
      }
    }
    
    <ListView KeyboardNavigation.TabNavigation="Cycle">
      <ListView.View>
        <GridView x:Name="gridView" AllowsColumnReorder="True">
          <local:CustomGridViewColumn Header="One" x:Name="col1">
            <local:CustomGridViewColumn.CellTemplate>
              <DataTemplate>
                <TextBox Width="100" Text="1" TabIndex="{Binding Path=ColumnIndex, Mode=OneWay, ElementName=col1}"/>
              </DataTemplate>
            </local:CustomGridViewColumn.CellTemplate>
          </local:CustomGridViewColumn>
          <local:CustomGridViewColumn Header="Two" x:Name="col2">
            <local:CustomGridViewColumn.CellTemplate>
              <DataTemplate>
                <TextBox Width="100" Text="2" TabIndex="{Binding Path=ColumnIndex, Mode=OneWay, ElementName=col2}"/>
              </DataTemplate>
            </local:CustomGridViewColumn.CellTemplate>
          </local:CustomGridViewColumn>
          <local:CustomGridViewColumn Header="Three" x:Name="col3">
            <local:CustomGridViewColumn.CellTemplate>
              <DataTemplate>
                <TextBox Width="100" Text="3" TabIndex="{Binding Path=ColumnIndex, Mode=OneWay, ElementName=col3}"/>
              </DataTemplate>
            </local:CustomGridViewColumn.CellTemplate>
          </local:CustomGridViewColumn>
        </GridView>
      </ListView.View>
    
      <ListViewItem>1</ListViewItem>
      <ListViewItem>2</ListViewItem>
      <ListViewItem>3</ListViewItem>
    </ListView>
    

    hope this helps