PowerShell WPF DataGrid: исключение, вызванное фиксацией пустой строки

Я получаю исключение при попытке зафиксировать пустую строку DataGrid.

System.NullReferenceException: Object reference not set to an instance of an object.
   at MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid()
   at MS.Internal.Data.PropertyPathWorker.get_IsDBNullValidForUpdate()
   at MS.Internal.Data.ClrBindingWorker.get_IsDBNullValidForUpdate()
   at System.Windows.Data.BindingExpression.ConvertProposedValue(Object value)
   at System.Windows.Data.BindingExpressionBase.UpdateValue()
   at System.Windows.Data.BindingExpression.Update(Boolean synchronous)
   at System.Windows.Data.BindingExpression.UpdateSource()
   at Microsoft.Windows.Controls.DataGridHelper.UpdateSource(FrameworkElement element, DependencyProperty dp)
   at Microsoft.Windows.Controls.DataGridTextColumn.CommitCellEdit(FrameworkElement editingElement)
   at Microsoft.Windows.Controls.DataGridColumn.CommitEdit(FrameworkElement editingElement)
   at Microsoft.Windows.Controls.DataGridCell.CommitEdit()
   at Microsoft.Windows.Controls.DataGrid.OnExecutedCommitEdit(ExecutedRoutedEventArgs e)
   at Microsoft.Windows.Controls.DataGrid.OnExecutedCommitEdit(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding)
   at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e)
   at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated)
   at System.Windows.Input.RoutedCommand.Execute(Object parameter, IInputElement target)
   at Microsoft.Windows.Controls.DataGrid.EndEdit(RoutedCommand command, DataGridCell cellContainer, DataGridEditingUnit editingUnit, Boolean exitEditMode)
   at Microsoft.Windows.Controls.DataGrid.CommitEdit(DataGridEditingUnit editingUnit, Boolean exitEditingMode)
   at Microsoft.Windows.Controls.DataGrid.CommitAnyEdit()
   at Microsoft.Windows.Controls.DataGrid.OnEnterKeyDown(KeyEventArgs e)
   at Microsoft.Windows.Controls.DataGrid.OnKeyDown(KeyEventArgs e)
   at System.Windows.UIElement.OnKeyDownThunk(Object sender, KeyEventArgs e)
   at System.Windows.Input.KeyEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawKeyboardActions actions, Int32 scanCode, Boolean isExtendedKey, Boolean isSystemKey, Int32 virtualKey)
   at System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(MSG& msg, Boolean& handled)
   at System.Windows.Interop.HwndSource.CriticalTranslateAccelerator(MSG& msg, ModifierKeys modifiers)
   at System.Windows.Interop.HwndSource.OnPreprocessMessage(Object param)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
Exception calling "Run" with "1" argument(s): "Object reference not set to an instance of an object."

Действия по воспроизведению:

  • Перейти к "новой строке"
  • Нажмите F2
  • Нажмите Ввод

Это работает нормально:

  • Перейти к "новой строке"
  • Нажмите F2
  • Нажмите ESC

Так же как:

  • Перейти к "новой строке"
  • Нажмите F2
  • Введите "sdfdsf"
  • Нажмите Ввод

Исходники можно найти здесь.

Я нашел два сообщения, которые, кажется, связаны с этой проблемой:

  1. Исключение в .Net 3.5 SP1
  2. Привязка данных WPF, типы классов, исключение пространства имен

Кроме того, я пробовал аналогичный код на С#, и он работал нормально.

Как я могу решить эту проблему?


person alex2k8    schedule 27.03.2009    source источник


Ответы (1)


Кажется, это ошибка в Microsoft WPF DataGrid. Обязательно сообщите об этом через Microsoft Connect, если вы еще этого не сделали.

В качестве обходного пути вы можете использовать преобразователь значений в своих привязках, чтобы предотвратить передачу значений NULL в целевом объекте привязки в источник привязки, что вызовет NullReferenceException. Вот пример такого преобразователя:

// NullToUnsetConverter.cs    

using System;
using System.Windows;
using System.Windows.Data;
using System.Globalization;

namespace MyProject.Controls.Converters
{
    /// <summary>
    /// Converts <c>null</c> values to <see cref="DependencyProperty.UnsetValue"/>.
    /// <remarks>
    /// This converter is intented for use in situations when the binding target
    /// does not correctly handle <c>null</c> values. This is the case for example
    /// with some WPF UI controls.
    /// </remarks>
    /// </summary>
    public class NullToUnsetConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
            {
                return DependencyProperty.UnsetValue;
            }
            else
            {
                // No conversion applied
                return value;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // No conversion applied
            return value;
        }
    }
}

Чтобы применить конвертер к вашим привязкам, вам придется изменить свой XAML следующим образом:

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:cnv="clr-namespace:MyProject.Controls.Converters"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WpfToolkit"
  >

  <Window.Resources>
    <x:Array x:Key="people" Type="sys:Object" />
    <cnv:NullToUnsetConverter x:Key="NullToUnsetConverter" />
  </Window.Resources>

  <StackPanel>
    <dg:DataGrid ItemsSource="{DynamicResource people}" CanUserAddRows="True" AutoGenerateColumns="False">
      <dg:DataGrid.Columns>

        <dg:DataGridTextColumn Header="First" Binding="{Binding First, Converter={StaticResource NullToUnsetConverter}}" />
        <dg:DataGridTextColumn Header="Last" Binding="{Binding Last, Converter={StaticResource NullToUnsetConverter}}" />

      </dg:DataGrid.Columns>
    </dg:DataGrid>
  </StackPanel>
</Window>

В качестве альтернативы вы можете изменить метод NullToUnsetConverter.Convert, чтобы он возвращал пустую строку, когда входное значение является строкой, как в вашем случае.

person Enrico Campidoglio    schedule 06.04.2009