Note that there are some explanatory texts on larger screens.

plurals
  1. POWPF datagrid arrow (right/left) key navigation exception
    primarykey
    data
    text
    <p>I am binding a WPF Datagrid's ItemsSource property to an ObservableCollection. The data gets pulled in fine but I notice strange behavior when I click on a cell (any cell) and start using the keyboard to navigate.</p> <ol> <li>Tab key works as expected (left-to-right and wraps to the next line down).</li> <li>Up key does nothing (focus stays on the selected cell).</li> <li>Down key shifts the focus to the top cell in the column. For example, if I'm on row 10 of column B and hit "down" then the focused cell becomes row 0 of column B.</li> <li>Left or right keys cause an ArgumentOutOfRangeException. "Specified argument was out of the range of valid values. Parameter name: index". There is no InnerException and the Stack Trace isn't much help either.</li> <li>Double-clicking any of the cells doesn't enable edit mode.</li> <li>For some reason I get an "extra" row (rowcount=(collection count +1)) at the bottom of the grid that has correct functionality (right/left buttons work, double-click triggers edit mode). When I double click to enter edit mode in this extra row and then click in a bound row above it, an extra row is added to the grid.</li> </ol> <p>I believe I've isolated the incident to the bound ViewModel class (as opposed to the XAML). In preliminary debugging I've stripped the XAML down to the bare minimum (no styles, 2 columns, only binding is the ItemsSource) and still get the weird behavior.</p> <pre><code>&lt;UserControl x:Name="FuelMileageView" x:Class="TRD.RaceStrategy.Views.FuelMileage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:TRD.RaceStrategy" xmlns:views="clr-namespace:TRD.RaceStrategy.Views" xmlns:vm="clr-namespace:TRD.RaceStrategy.ViewModels;assembly=RaceStrategy.Support" xmlns:converters="clr-namespace:TRD.RaceStrategy.Converters;assembly=RaceStrategy.Support" xmlns:Behaviours="clr-namespace:TRD.RaceStrategy.Behaviours;assembly=RaceStrategy.Support" mc:Ignorable="d" DataContext="{Binding Path=Properties[PrimaryVM].CarEventVM.FuelMileage.FuelMileageLaps, Source={x:Static local:App.Current}}" d:DesignHeight="410" d:DesignWidth="485"&gt; &lt;DataGrid x:Name="dgFMLaps" ItemsSource="{Binding}" AutoGenerateColumns="False"&gt; &lt;DataGrid.Columns&gt; &lt;DataGridTextColumn Header="Column 1" &gt; &lt;/DataGridTextColumn&gt; &lt;DataGridTextColumn Header="Column 2" &gt; &lt;/DataGridTextColumn&gt; &lt;/DataGrid.Columns&gt; &lt;/DataGrid&gt; &lt;/UserControl&gt; </code></pre> <p>Aside from the InitializeComponent() call there is no codebehind to speak of which seems to leave the bound FuelMileageLaps collection as the only culprit.</p> <pre><code>public class FuelMileageLapViewModel : LapViewModel { public FuelMileageLapViewModel() { } } </code></pre> <p>NOTE: ObservableCollectionEx is an extension of the ObservableCollection class which apparently accounts for threading problems (?) I've used this class with other collections that I've in turn plugged into datagrids that didn't have this keyboard navigation problem.</p> <pre><code>public class ObservableCollectionEx&lt;T&gt; : ObservableCollection&lt;T&gt; { // Override the event so this class can access it public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged; protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { // Be nice - use BlockReentrancy like MSDN said using (BlockReentrancy()) { System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged; if (eventHandler == null) return; Delegate[] delegates = eventHandler.GetInvocationList(); // Walk thru invocation list foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates) { DispatcherObject dispatcherObject = handler.Target as DispatcherObject; // If the subscriber is a DispatcherObject and different thread if (dispatcherObject != null &amp;&amp; dispatcherObject.CheckAccess() == false) { // Invoke handler in the target dispatcher's thread dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e); } else // Execute handler as is handler(this, e); } } } } </code></pre> <p>At this point I'm at my wit's end as to the next step for debugging. There's no obvious place to throw in a breakpoint or try/catch block. I've Googled my problem to death and haven't found anything worthwhile. Please help!</p> <p>Here's the FuelMileageViewModel class where FuelMileageLaps is initialized:</p> <pre><code>public class FuelMileageViewModel : WorkspaceViewModel { /// &lt;summary&gt; /// View model for the fuel mileage calculator /// &lt;/summary&gt; /// &lt;param name="car"&gt;Car on which to base all calculations&lt;/param&gt; public FuelMileageViewModel() {} /// &lt;summary&gt; /// A separate collection of laps that store the extra fuel mileage data /// &lt;/summary&gt; public ObservableCollectionEx&lt;FuelMileageLapViewModel&gt; FuelMileageLaps { get { if (_fuelMileageLaps == null) { _fuelMileageLaps = new ObservableCollectionEx&lt;FuelMileageLapViewModel&gt;(); } return _fuelMileageLaps; } set { _fuelMileageLaps = value; OnPropertyChanged("FuelMileageLaps"); } } private ObservableCollectionEx&lt;FuelMileageLapViewModel&gt; _fuelMileageLaps; /// &lt;summary&gt; /// Number of laps in the race /// Affects: Laps_G, Laps_Y /// &lt;/summary&gt; public int NumberOfLaps { get { return FuelMileageLaps.Count; } set { int count = FuelMileageLaps.Count; if (value &lt; 0) { throw new ArgumentException("Number of laps must be a positive integer"); } if (count != value) { if( count &lt; value ) { int diff = value - count; for (int i = 0; i &lt; diff; i++) { FuelMileageLapViewModel lapToAdd = new FuelMileageLapViewModel(); FuelMileageLaps.Add(lapToAdd); } } OnPropertyChanged("NumberOfLaps"); } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload