Исключение навигации по клавише стрелки WPF (вправо / влево) - PullRequest
2 голосов
/ 17 января 2011

Я связываю свойство ItemsSource WPF Datagrid с ObservableCollection. Данные извлекаются нормально, но я замечаю странное поведение, когда нажимаю на ячейку (любую ячейку) и начинаю использовать клавиатуру для навигации.

  1. Клавиша Tab работает как положено (слева направо и переносится на следующую строку вниз).
  2. Клавиша «вверх» ничего не делает (фокус остается на выбранной ячейке).
  3. Клавиша «Вниз» перемещает фокус на верхнюю ячейку в столбце. Например, если я нахожусь в строке 10 столбца B и нажимаю «вниз», то выделенная ячейка становится строкой 0 столбца B.
  4. Левая или правая клавиши вызывают исключение ArgumentOutOfRangeException. Msgstr "Указанный аргумент вышел за пределы допустимых значений. Имя параметра: индекс". InnerException не существует, и трассировка стека также мало чем поможет.
  5. Двойной щелчок по любой из ячеек не включает режим редактирования.
  6. По какой-то причине в нижней части сетки появляется «лишняя» строка (rowcount = (count collection +1)), которая имеет правильную функциональность (работают кнопки вправо / влево, режим редактирования триггеров двойного щелчка). Когда я дважды щелкаю, чтобы войти в режим редактирования в этой дополнительной строке, а затем щелкаю в связанной строке над ней, в сетку добавляется дополнительная строка.

Я полагаю, что я изолировал инцидент с связанным классом ViewModel (в отличие от XAML). В предварительной отладке я сократил XAML до минимума (без стилей, 2 столбца, только связывание - это ItemsSource) и все еще получаю странное поведение.

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

<DataGrid x:Name="dgFMLaps" ItemsSource="{Binding}"
            AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Column 1" >
        </DataGridTextColumn>
        <DataGridTextColumn Header="Column 2" >
        </DataGridTextColumn>
    </DataGrid.Columns>            
</DataGrid>
</UserControl>

Помимо вызова InitializeComponent (), нет никакого кода, о котором можно было бы говорить, который, кажется, оставляет связанную коллекцию FuelMiletLaps единственным виновником.

public class FuelMileageLapViewModel : LapViewModel
{
    public FuelMileageLapViewModel() { }    
}

ПРИМЕЧАНИЕ. ObservableCollectionEx - это расширение класса ObservableCollection, которое, по-видимому, объясняет проблемы с многопоточностью (?) Я использовал этот класс с другими коллекциями, которые, в свою очередь, подключены к сетям данных, у которых не было этой проблемы навигации по клавиатуре.

public class ObservableCollectionEx<T> : ObservableCollection<T>
{
    // 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 && 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);
            }
        }
    }
}

На данный момент я нахожусь в конце своего ума относительно следующего шага для отладки. Там нет очевидного места, чтобы бросить в точку останова или блок try / catch. Я погуглил свою проблему до смерти и не нашел ничего стоящего. Пожалуйста, помогите!

Вот класс FuelMiletViewModel, в котором инициализируется FuelMiletLaps:

public class FuelMileageViewModel : WorkspaceViewModel
{
    /// <summary>
    /// View model for the fuel mileage calculator
    /// </summary>
    /// <param name="car">Car on which to base all calculations</param>
    public FuelMileageViewModel()
    {}

    /// <summary>
    /// A separate collection of laps that store the extra fuel mileage data
    /// </summary>
    public ObservableCollectionEx<FuelMileageLapViewModel> FuelMileageLaps
    {
        get
        {
            if (_fuelMileageLaps == null)
            {
                _fuelMileageLaps = new ObservableCollectionEx<FuelMileageLapViewModel>();
            }
            return _fuelMileageLaps;
        }
        set
        {
            _fuelMileageLaps = value;
            OnPropertyChanged("FuelMileageLaps");
        }
    }
    private ObservableCollectionEx<FuelMileageLapViewModel> _fuelMileageLaps;

    /// <summary>
    /// Number of laps in the race
    /// Affects: Laps_G, Laps_Y
    /// </summary>
    public int NumberOfLaps
    {
        get
        {
            return FuelMileageLaps.Count;
        }
        set
        {
            int count = FuelMileageLaps.Count;

            if (value < 0)
            {
                throw new ArgumentException("Number of laps must be a positive integer");
            }

            if (count != value)
            {
                if( count < value )
                {
                    int diff = value - count;
                    for (int i = 0; i < diff; i++)
                    {
                        FuelMileageLapViewModel lapToAdd = new FuelMileageLapViewModel();

                        FuelMileageLaps.Add(lapToAdd);
                    }
                }
                OnPropertyChanged("NumberOfLaps");
            }
        }
    }
}

1 Ответ

0 голосов
/ 22 марта 2013

Я знаю, что это старый вопрос, но недавно у меня были ОЧЕНЬ похожие проблемы с DataGrid. Проблемы со стрелками были такими же, как вы описали. Однако я использовал DataGridTemplateColumns, в котором TextBox разрешено редактировать (иначе, как вы заметили, я не мог редактировать данные). Если бы я отредактировал ячейку, а затем щелкнул по ней (особенно если щелкнул строку над ней), DataGrid часто выдает дублирующую строку (хотя количество в коллекции остается неизменным).

В моем случае я обнаружил ошибку в своем методе Equals (object obj) для класса, члены которого были в ObservableCollection, привязанными к DataGrid. Это предотвратило призывы к Equals определить истинное равенство между двумя предметами, и почему-то это вызвало большие проблемы. Например, если после редактирования строки сетка данных не может найти ту же строку уже в своем списке (посредством вызовов ошибочного метода Equals), возможно, она генерирует другую строку (при условии, что для этой записи еще не должно быть строки) .

В любом случае, я бы предложил проверить метод Equals в вашей LapViewModel.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...