I have the following xaml and c#.
I use DataGrid and RowDetailsTemplate with another DataGrid.
The parent grid with Person information, the child grid has cars owned by the person.
I
got some of this code from another post, I changed it and am looking to
be able to navigate between persons and cars using the up/down arrows.
I am getting all kind of focus issues and not able to move between different persons and cars.
Can anyone tell me what I am doing wrong, and how to accomplish what I want.
Thanks in advance.
XAML----------------------------------------------
<Window x:Class="DataGridEx2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridEx2"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
x:Name="objDatagrid"
ItemsSource="{Binding DataView}"
Background="White"
CanUserAddRows="False"
CanUserDeleteRows="False"
RowDetailsVisibilityMode="Visible"
FontFamily="Arial" FontSize="20"
GridLinesVisibility="All"
IsReadOnly="True"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Continue"
ScrollViewer.IsDeferredScrollingEnabled="True"
ScrollViewer.CanContentScroll="False"
IsSynchronizedWithCurrentItem="True"
CanUserSortColumns="False"
SelectedItem="{Binding SelectedPerson,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
IsTabStop="True"
SelectionUnit="FullRow"
AutoGenerateColumns="False" BorderThickness="0"
CanUserReorderColumns="False" CanUserResizeColumns="False"
SelectionMode="Single" CanUserResizeRows="False"
PreviewKeyDown="objDatagrid_PreviewKeyDown"
SelectionChanged="objDatagrid_SelectionChanged" >
<DataGrid.RowDetailsTemplate >
<DataTemplate DataType="{x:Type local:Person}">
<DataGrid x:Name="objInnerDatagrid" Height="Auto" Padding="0"
ItemsSource="{Binding Cars}"
Background="White"
CanUserAddRows="False"
CanUserDeleteRows="False"
RowDetailsVisibilityMode="Visible"
FontFamily="Arial" FontSize="20"
GridLinesVisibility="All"
IsReadOnly="True"
KeyboardNavigation.TabNavigation="Local"
ScrollViewer.IsDeferredScrollingEnabled="True"
ScrollViewer.CanContentScroll="False"
IsSynchronizedWithCurrentItem="True"
SelectionUnit="FullRow"
IsTabStop="True"
CanUserSortColumns="False"
AutoGenerateColumns="False" BorderThickness="0" ClipToBounds="True"
SnapsToDevicePixels="True" HeadersVisibility="None"
CanUserReorderColumns="False" CanUserResizeColumns="False"
SelectionMode="Single" PreviewKeyDown="objInnerDatagrid_PreviewKeyDown"
SelectionChanged="objInnerDatagrid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Width="100" Binding="{Binding Model}"
CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
<DataGridTextColumn Width="100" Binding="{Binding Year}"
CanUserSort="False" CanUserResize="False" CanUserReorder="False" />
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="GotFocus" Handler="GotFocusRowDetails"/>
</Style>
</DataGrid.RowStyle>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="SelectRowDetails"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Width="100" Binding="{Binding FirstName}" IsReadOnly="False"/>
<DataGridTextColumn Header="Last Name" Width="100" Binding="{Binding LastName}" IsReadOnly="False"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button VerticalAlignment="Center" x:Name="btnAddCar" Width="80"
Height="30" Content="Add Carr" Click="btnAddCar_Click" />
<Button Content="Delete Car" x:Name="btnDeleteCar" Width="80"
Height="30" VerticalAlignment="Center" HorizontalAlignment="Left"
Margin="20,0,0,0" Click="btnDeleteCar_Click" />
<Button Content="Delete Person" x:Name="btnDeletePerson" Width="80"
Margin="140,0,0,0" Height="30" Click="btnDeletePerson_Click"/>
<Button Content="Add Person" x:Name="btnAddPerson" Width="80"
Margin="20,0,0,0" Height="30" Click="btnAddPerson_Click" />
</StackPanel>
</Grid>
</Window>
C#-----------------------------------------------------------
using System;using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DataGridEx2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DataGrid _innerGrid;
private DataGrid _outerGrid = null;
ObservableCollection<Person> people;
public MainWindow()
{
InitializeComponent();
DataContext = this;
_innerGrid = this.FindName("objInnerDatagrid") as DataGrid;
_outerGrid = this.FindName("objDatagrid") as DataGrid;
people = CreateData();
_dataView = new ListCollectionView(people);
}
private ObservableCollection<Person> CreateData()
{
return new ObservableCollection<Person>()
{
new Person
{
FirstName = "Davide",
LastName = "Seddio",
Nationality="CH",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Toyota", Year = 1977},
new Car {Model = "Mazda", Year = 1982}
}
},
new Person
{
FirstName = "Luca",
LastName = "Bianchi",
Nationality = "CH",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Fiat", Year = 1977},
new Car {Model = "Ford", Year = 1982},
new Car {Model = "BMW", Year = 1980}
}
},
new Person
{
FirstName = "Marco",
LastName = "Milani",
Nationality = "CH",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Suzuki", Year = 1977},
new Car {Model = "Subaru", Year = 1982}
}
},
new Person
{
FirstName = "Alfred",
LastName = "Zurcher",
Nationality = "CH",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Mercedes", Year = 1977},
new Car {Model = "Ferrari", Year = 1982}
}
},
new Person
{
FirstName = "Franco",
LastName = "Veri",
Nationality = "IT",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Audi", Year = 1977},
new Car {Model = "BMW", Year = 1982}
}
},
new Person
{
FirstName = "Luigi",
LastName = "Mulinelli",
Nationality = "IT",
Cars = new ObservableCollection<Car>
{
new Car {Model = "VW", Year = 1977},
new Car {Model = "Jaguar", Year = 1982}
}
},
new Person
{
FirstName = "Carlo",
LastName = "Zanfrini",
Nationality = "IT",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Autobianchi", Year = 1977},
new Car {Model = "Lancia", Year = 1982}
}
},
new Person
{
FirstName = "Alex",
LastName = "Calderoli",
Nationality = "DE",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Alfa Romeo", Year = 1977},
new Car {Model = "Renault", Year = 1982}
}
},
new Person
{
FirstName = "Andrea",
LastName = "Laranguate",
Nationality = "FR",
Cars = new ObservableCollection<Car>
{
new Car {Model = "Peugeot", Year = 1977},
new Car {Model = "Citroen", Year = 1982}
}
},
new Person
{
FirstName = "Oreste",
LastName = "Tranquilli",
Nationality = "EN",
Cars = new ObservableCollection<Car>()
//Cars = new ObservableCollection<Car>()
//{
// new Car {Model = "Saab", Year = 1977},
// new Car {Model = "Lamborghini", Year = 1982}
//}
}
};
}
private Person _selectedPerson;
public Person SelectedPerson
{
get { return _selectedPerson; }
set { _selectedPerson = value;
if(value != null)
Console.WriteLine("Selected Person = " + value.LastName+" Selected Car =
"+((SelectedCar !=null)?SelectedCar.Model:""));
}
}
private Car _selectedCar;
public Car SelectedCar
{
get { return _selectedCar; }
set
{
_selectedCar = value; if (value != null) Console.WriteLine("Selected
Car = " + value.Model+" Selected Person = "+((SelectedPerson
!=null)?SelectedPerson.LastName:""));
}
}
private ListCollectionView _dataView;
public ListCollectionView DataView
{
get { return _dataView; }
set { _dataView = value; }
}
private void objDatagrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
Console.WriteLine("OUTER PreviewKeyDown");
//if (Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.Tab)
//{
// DataGrid originalDataGrid = null;
// if (e.OriginalSource is DataGridCell)
// {
// originalDataGrid = VisualControlsAccess.GetDataGridFromCell((DataGridCell)e.OriginalSource);
// }
// if (originalDataGrid != null && !originalDataGrid.Name.Equals(_outerGrid.Name))
// {
// Console.WriteLine("Outer PreviewKeyDown selectedIndex" + originalDataGrid.SelectedIndex);
// ////originalDataGrid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
// //DataGridRow row = VisualControlsAccess.GetDataGridRowFromCell((DataGridCell)e.OriginalSource);
// //row.Focus();
// }
// else
// _outerGrid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
// e.Handled = true;
//}
//else if (Keyboard.Modifiers == ModifierKeys.None && e.Key == Key.Tab)
//{
// (Keyboard.FocusedElement as FrameworkElement).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
// e.Handled = true;
//}
if (e.Key == Key.Down)
{
DataGrid grid = (DataGrid)e.Source;
if (grid.SelectedItem == null)
{
Console.WriteLine("1");
grid = (DataGrid)sender;
}
if (grid.SelectedItem is Person)
{
SelectedPerson = ((Person)grid.SelectedItem);
if (((Person)grid.SelectedItem).Cars.Count() > 0)
{
Console.WriteLine("2");
DataGridCellInfo selectedDataGridCellInfo = (grid.SelectedCells[0] as DataGridCellInfo?).Value;
DataGridRow rowContainer =
(DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(selectedDataGridCellInfo.Item);
if (rowContainer != null)
{
Console.WriteLine("3");
DataGrid innerGrid = VisualControlsAccess.GetVisualChild<DataGrid>(rowContainer);
if (innerGrid != null)
{
Console.WriteLine("4");
if (innerGrid.Items != null && innerGrid.Items.Count > 0)
{
DataGridRow row = ((DataGridRow)innerGrid.ItemContainerGenerator.ContainerFromIndex(0));
DataGridCellsPresenter presenter =
VisualControlsAccess.GetVisualChild<DataGridCellsPresenter>(row);
if (presenter != null)
{
Console.WriteLine("5");
DataGridCell cell =
(System.Windows.Controls.DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(0);
if (cell != null)
{
Console.WriteLine("6");
//row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
// Focus on the First Cell of the First InnerGrid Row
FocusManager.SetFocusedElement(innerGrid, cell as IInputElement);
innerGrid.SelectedIndex = 0;
row.Focus();
//FocusManager.SetIsFocusScope(cell, true);
//FocusManager.SetIsFocusScope(row, true);
//FocusManager.SetFocusedElement(innerGrid, row as IInputElement);
FocusManager.SetFocusedElement(innerGrid, row);
// Mark this event as handled.
e.Handled = true;
// Remove the selection from the outerGrid row.
this.Dispatcher.BeginInvoke((Action)(() =>
{
objDatagrid.SelectedIndex = -1;
}), null);
}
}
}
//DataGridCell cell = (System.Windows.Controls.DataGridCell)presenter
}
//DataGridCellsPresenter presenter =
VisualControlsAccess.GetVisualChild<DataGridCellsPresenter>(rowContainer);
//if (presenter != null)
//{
// DataGridCell cell =
(System.Windows.Controls.DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(0);
//}
}
//e.Handled = true;
}
}
}
else if (e.Key == Key.Up)
{
DataGrid grid = (DataGrid)e.Source;
if (grid.SelectedItem is Person)
{
SelectedPerson = ((Person)grid.SelectedItem);
}
}
else if (e.Key == Key.Left || e.Key == Key.Right)
{
//Ignore Left and Right keys while in the DataGrid.
e.Handled = true;
}
}
private void objInnerDatagrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
Console.WriteLine("INNER PreviewKeyDown");
if (e.Source is ItemsPresenter)
{
// Get the Selected Person from the DataContext.
SelectedPerson = ((Person)((ItemsPresenter)e.Source).DataContext);
}
}
//////////////////// PROBLEMS and FIXES //////////////////////
////// Mouse click focus on Inner row ////////////////////////
/// Fix, when the row selected is the outer Grid row, do nothing.
/// If the row selected is a inner grid row, the control tries to highlight both, inner and outer,
/// this will set the focus to the inner grid and remove focus from the outer grid.
private void SelectRowDetails(object sender, MouseButtonEventArgs e)
{
var rowSource = e.Source;
if (rowSource is DataGridCellsPresenter)
{
Console.WriteLine("SelectRowDetails 1");
}
else if (rowSource is DataGridDetailsPresenter)
{
Console.WriteLine("SelectRowDetails 2");
// Row selected is a Inner datagrid
DataGridRow row = sender as DataGridRow;
row.Focusable = true;
bool focused = row.Focus();
if (SelectedPerson == null)
{
// If first selection is an inner item, get the person from it.
SelectedPerson = (Person)row.Item;
}
// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
// Change keyboard focus.
if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
// Remove the focus from the outer row
this.Dispatcher.BeginInvoke((Action)(() =>
{
objDatagrid.SelectedIndex = -1;
}), null);
}
}
/// <summary>
/// Used to get the focused RowDetails
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void GotFocusRowDetails(object sender, RoutedEventArgs e)
{
SelectedCar = ((Car)((DataGridRow)sender).Item);
}
private void objDatagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Console.WriteLine("OUTER SelectionChanged");
}
private void btnAddCar_Click(object sender, RoutedEventArgs e)
{
Person pers = (Person)_outerGrid.SelectedItem;
//Person pers = people.ToList().Find(p => p.FirstName.Equals("Oreste"));
if (pers != null)
{
pers.Cars.Add(new Car { Model = "Lamborghini", Year = 1982 });
}
}
private void btnDeleteCar_Click(object sender, RoutedEventArgs e)
{
var pers = _outerGrid.SelectedItem;
if (pers != null)
{
int indx = people.ToList().FindIndex(p => ((Person)p).FirstName.Equals(((Person)pers).FirstName));
if (indx >= 0)
{
people.RemoveAt(indx);
}
}
}
private void btnDeletePerson_Click(object sender, RoutedEventArgs e)
{
var pers = SelectedPerson;
if (pers != null)
{
int indx = people.ToList().FindIndex(p => ((Person)p).FirstName.Equals(((Person)pers).FirstName));
if (indx >= 0)
{
people.RemoveAt(indx);
}
}
}
int persNum = 0;
private void btnAddPerson_Click(object sender, RoutedEventArgs e)
{
people.Add(new Person
{
FirstName = "FirstName [ " + persNum + " ]",
LastName = "LastName [ " + persNum + " ]",
Nationality = "" + persNum,
Cars = new ObservableCollection<Car>
{
new Car {Model = "Car1 ["+persNum+" ]", Year = 1977},
new Car {Model = "Car2 ["+persNum+" ]", Year = 1982}
}
});
persNum++;
}
private void objInnerDatagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Not needed, set in GetFocusRowDetails
//SelectedCar = (Car)((DataGrid)sender).SelectedItem;
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Nationality { get; set; }
public ObservableCollection<Car> Cars { get; set; }
}
public class Car
{
public string Model { get; set; }
public int Year { get; set; }
}
}