Комбинация SelectedItem DataBinding NullReference Exception
Сейчас я немного расстроен с помощью combobox и надеюсь, что у кого-то есть ответ на мой вопрос. Проблема заключается в SelectedItem. Когда я запускаю свое приложение в отладчике, он будет генерировать исключение с ссылкой на null, если я введу текст в ComboBox, который соответствует элементу (то есть.. a, b или c) в элементах, а затем удалит текст. Если я ввожу текст в ComboBox, и это не соответствует, а Item (ie.. z) в Items, а затем удаляет текст, он не падает. Такое поведение происходит только в отладчике. Если я запустил приложение за пределами, я не сбой. Я использую mvvmlight takeit, но я не думаю, что это имеет к этому какое-то отношение. Мой код ниже
Вид:
<ComboBox IsEditable="True"
VerticalAlignment="Top"
ItemsSource="{Binding Items}"
DisplayMemberPath="Name"
SelectedItem="{Binding Item,Mode=TwoWay}"/>
Модель:
public class Item
{
public string Name { get; set; }
public int Id { get; set; }
}
VM:
public MainViewModel()
{
Items = new List<Item>
{
new Item {Name="a", Id=0},
new Item {Name="b", Id=1},
new Item {Name="c", Id=2},
};
}
/// <summary>
/// The <see cref="Items" /> property name.
/// </summary>
public const string ItemsPropertyName = "Items";
private List<Item> _items;
/// <summary>
/// Sets and gets the Items property.
/// Changes to that property value raise the PropertyChanged event.
/// </summary>
public List<Item> Items
{
get
{
return _items;
}
set
{
Set(ItemsPropertyName, ref _items, value);
}
}
/// <summary>
/// The <see cref="Item" /> property name.
/// </summary>
public const string ItemPropertyName = "Item";
private Item _item;
/// <summary>
/// Sets and gets the Item property.
/// Changes to that property value raise the PropertyChanged event.
/// </summary>
public Item Item
{
get
{
return _item;
}
set
{
Set(ItemPropertyName, ref _item, value);
}
}
Ответы
Ответ 1
Это ошибка в .NET Framework 4 (и .NET 4.5, не в .NET 3.0 и .NET 3.5).
Метод PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid(object item)
вызывает проблему.
Посмотрев на .NET Reflector, его код выглядит так:
private bool DetermineWhetherDBNullIsValid(object item)
{
PropertyInfo info;
PropertyDescriptor descriptor;
DependencyProperty property;
DynamicPropertyAccessor accessor;
this.SetPropertyInfo(this._arySVS[this.Length - 1].info, out info, out descriptor, out property, out accessor);
string columnName = (descriptor != null) ? descriptor.Name : ((info != null) ? info.Name : null);
object arg = ((columnName == "Item") && (info != null)) ? this._arySVS[this.Length - 1].args[0] : null;
return SystemDataHelper.DetermineWhetherDBNullIsValid(item, columnName, arg);
}
Проблема находится в следующей строке:
object arg = ((columnName == "Item") && (info != null)) ? this._arySVS[this.Length - 1].args[0] : null;
Код предполагает, что если columnName
является "Item"
, тогда свойство является индексом и пытается получить доступ к его первому аргументу через args[0]
, и это происходит там, где NullReferenceException
происходит, потому что args
есть null
, поскольку свойство не индексатор. Это просто называется "Item"
.
Разработчики .NET должны были использовать PropertyInfo.GetIndexParameters() в info
, и если возвращенный массив не содержит нулевых элементов, сделайте определенные предположение, что свойство является индексатором. Или используйте Binding.IndexerName для проверки (Binding.IndexerName имеет значение "Item[]"
).
Почему выдача возникает только в отладчике Visual Studio, гораздо более тонкая и скрыта в следующем методе:
PresentationFramework.dll! MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid().
Вот разобранный код:
private void DetermineWhetherDBNullIsValid()
{
bool flag = false;
object item = this.GetItem(this.Length - 1);
if ((item != null) && AssemblyHelper.IsLoaded(UncommonAssembly.System_Data))
{
flag = this.DetermineWhetherDBNullIsValid(item);
}
this._isDBNullValidForUpdate = new bool?(flag);
}
Так как переменная item
не будет нулевой (это фактически экземпляр WeakReference, который содержит экземпляр MainViewModel
), вызывается только условие, для которого вызывается метод отказа DetermineWhetherDBNullIsValid(item)
, если загружена сборка System.Data.dll, которая проверяется с помощью AssemblyHelper.IsLoaded(UncommonAssembly.System_Data)
.
Отладчик Visual Studio всегда будет загружать System.Data.dll, потому что проект ссылается на него, хотя он не использует его.
Вне отладчика Visual Studio System.Data.dll загружается только в том случае, если он используется, а это никогда не происходит, и поэтому приложение не выходит за пределы Visual Studio.
У вас есть следующие варианты, чтобы избавиться от этой проблемы:
- Переименуйте свойство, которое привязано к
ComboBox.SelectedItem
к некоторому имени, отличному от "Item"
, так что реализация buggy.NET не предполагает, что это свойство является индексом.
- Удалите System.Data.dll из ссылок на проекты, чтобы он не загружался даже в отладчике Visual Studio.
Я нахожу вариант 2 более хрупким, так как может возникнуть ситуация, когда файл System.Data.dll должен быть загружен либо напрямую вашим приложением, либо косвенно с помощью другой загруженной сборки.
Итак, я бы пошел с вариантом 1.
Ответ 2
Я могу воспроизвести это на моей стороне. Добавьте это в свой код со списком:
IsTextSearchEnabled="False"
В любом случае, кто еще интересуется этой проблемой, stacktrace для этого исключения выглядит следующим образом
PresentationFramework.dll! MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid(объект объекта) + 0xc7 байт
PresentationFramework.dll! MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid() + 0x64 байт
PresentationFramework.dll! MS.Internal.Data.PropertyPathWorker.IsDBNullValidForUpdate.get() + 0x2e байт PresentationFramework.dll! MS.Internal.Data.ClrBindingWorker.IsDBNullValidForUpdate.get() + 0xa байт
PresentationFramework.dll! System.Windows.Data.BindingExpression.ConvertProposedValue(значение объекта) + 0x177 байт
PresentationFramework.dll! System.Windows.Data.BindingExpressionBase.UpdateValue() + 0x92 байт
PresentationFramework.dll! System.Windows.Data.BindingExpression.UpdateOverride() + 0x3d байт
PresentationFramework.dll! System.Windows.Data.BindingExpressionBase.Update() + 0x20 байт
PresentationFramework.dll! System.Windows.Data.BindingExpressionBase.ProcessDirty() + 0x2f байт PresentationFramework.dll! System.Windows.Data.BindingExpressionBase.Dirty() + 0x40 байт
PresentationFramework.dll! System.Windows.Data.BindingExpressionBase.SetValue(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, значение объекта) + 0x24 байт
WindowsBase.dll! System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, значение объекта, метаданные System.Windows.PropertyMetadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) + 0x3c4 bytes
WindowsBase.dll! System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp, значение объекта) + 0x35 байт
PresentationFramework.dll! System.Windows.Controls.Primitives.Selector.UpdatePublicSelectionProperties() + 0x13f байт
PresentationFramework.dll! System.Windows.Controls.Primitives.Selector.SelectionChanger.End() + 0x80 байт
PresentationFramework.dll! System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(System.Windows.Controls.ItemsControl.ItemInfo info, bool acceptInItemsCollection) + 0x145 байт
PresentationFramework.dll! System.Windows.Controls.Primitives.Selector.OnSelectedIndexChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e) + 0xd9 байт
WindowsBase.dll! System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x4d байт PresentationFramework.dll! System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x50 байт
WindowsBase.dll! System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) + 0x3b байт
WindowsBase.dll! System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex, System.Windows.DependencyProperty dp, метаданные System.Windows.PropertyMetadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType) + 0x757 байтов
WindowsBase.dll! System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, значение объекта, метаданные System.Windows.PropertyMetadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) + 0x2ea bytes
WindowsBase.dll! System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp, значение объекта) + 0x35 байт
PresentationFramework.dll! System.Windows.Controls.ComboBox.TextUpdated(строка newText, bool textBoxUpdated) + 0x26e байт
PresentationFramework.dll! System.Windows.Controls.ComboBox.OnEditableTextBoxTextChanged(отправитель объекта, System.Windows.Controls.TextChangedEventArgs e) + 0x2e байт PresentationFramework.dll! System.Windows.Controls.TextChangedEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x2c байты
PresentationCore.dll! System.Windows.RoutedEventArgs.InvokeHandler(обработчик System.Delegate, объект-объект) + 0x33 байт
PresentationCore.dll! System.Windows.RoutedEventHandlerInfo.InvokeHandler(объект target, System.Windows.RoutedEventArgs routedEventArgs) + 0x44 байт
PresentationCore.dll! System.Windows.EventRoute.InvokeHandlersImpl(источник объекта, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1a8 байт
PresentationCore.dll! System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject отправитель, System.Windows.RoutedEventArgs args) + 0x73 байт
PresentationCore.dll! System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs e) + 0x29 байт PresentationFramework.dll! System.Windows.Controls.Primitives.TextBoxBase.OnTextChanged(System.Windows.Controls.TextChangedEventArgs e) + 0x5 байт
PresentationFramework.dll! System.Windows.Controls.Primitives.TextBoxBase.OnTextContainerChanged(отправитель объекта, System.Windows.Documents.TextContainerChangedEventArgs e) + 0xe0 байт
PresentationFramework.dll! System.Windows.Controls.TextBox.OnTextContainerChanged(отправитель объекта, System.Windows.Documents.TextContainerChangedEventArgs e) + 0x17d байт PresentationFramework.dll! System.Windows.Documents.TextContainer.EndChange(bool skipEvents) + 0xb6 байт
PresentationFramework.dll! System.Windows.Documents.TextContainer.System.Windows.Documents.ITextContainer.EndChange(bool skipEvents) + 0xb байт PresentationFramework.dll! System.Windows.Documents.TextRangeBase.EndChange(System.Windows.Documents.ITextRange thisRange, bool disableScroll, bool skipEvents) + 0x59 байт PresentationFramework.dll! System.Windows.Documents.TextRange.System.Windows.Documents.ITextRange.EndChange(bool disableScroll, bool skipEvents) + 0x11 байт
PresentationFramework.dll! System.Windows.Documents.TextRange.ChangeBlock.System.IDisposable.Dispose() + 0x15 байт
PresentationFramework.dll! System.Windows.Documents.TextEditorTyping.OnDelete(объектный отправитель, System.Windows.Input.ExecutedRoutedEventArgs args) + 0x1a7 байт
PresentationCore.dll! System.Windows.Input.CommandBinding.OnExecuted(отправитель объекта, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x65 байт PresentationCore.dll! System.Windows.Input.CommandManager.ExecuteCommandBinding(отправитель объекта, System.Windows.Input.ExecutedRoutedEventArgs e, System.Windows.Input.CommandBinding commandBinding) + 0x92 байт
PresentationCore.dll! System.Windows.Input.CommandManager.FindCommandBinding(System.Windows.Input.CommandBindingCollection commandBindings, отправитель объекта, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand command, bool execute) + 0x105 bytes
PresentationCore.dll! System.Windows.Input.CommandManager.FindCommandBinding(отправитель объекта, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand command, bool execute) + 0x15e байт PresentationCore.dll! System.Windows.Input.CommandManager.OnExecuted(отправитель объекта, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x25 байт PresentationCore.dll! System.Windows.UIElement.OnExecutedThunk(отправитель объекта, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x46 байт
PresentationCore.dll! System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(System.Delegate genericHandler, цель объекта) + 0x3c байтов
PresentationCore.dll! System.Windows.RoutedEventArgs.InvokeHandler(обработчик System.Delegate, объект-объект) + 0x33 байт
PresentationCore.dll! System.Windows.RoutedEventHandlerInfo.InvokeHandler(объект target, System.Windows.RoutedEventArgs routedEventArgs) + 0x44 байт
PresentationCore.dll! System.Windows.EventRoute.InvokeHandlersImpl(источник объекта, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1a8 байт
PresentationCore.dll! System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject отправитель, System.Windows.RoutedEventArgs args) + 0x73 байт
PresentationCore.dll! System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) + 0x3d байт
PresentationCore.dll! System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x40 байт
PresentationCore.dll! System.Windows.Input.RoutedCommand.ExecuteImpl(параметр объекта, объект System.Windows.IInputElement, bool userInitiated) + 0x105 байт
PresentationCore.dll! System.Windows.Input.RoutedCommand.ExecuteCore(объект-параметр, System.Windows.IInputElement target, bool userInitiated) + 0x59 байт PresentationCore.dll! System.Windows.Input.CommandManager.TranslateInput(System.Windows.IInputElement targetElement, System.Windows.Input.InputEventArgs inputEventArgs) + 0x59b байт
PresentationCore.dll! System.Windows.UIElement.OnKeyDownThunk(отправитель объекта, System.Windows.Input.KeyEventArgs e) + 0x52 байт
PresentationCore.dll! System.Windows.Input.KeyEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x2c байты
PresentationCore.dll! System.Windows.RoutedEventArgs.InvokeHandler(обработчик System.Delegate, объект-объект) + 0x33 байт
PresentationCore.dll! System.Windows.RoutedEventHandlerInfo.InvokeHandler(объект target, System.Windows.RoutedEventArgs routedEventArgs) + 0x44 байт
PresentationCore.dll! System.Windows.EventRoute.InvokeHandlersImpl(источник объекта, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1a8 байт
PresentationCore.dll! System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject отправитель, System.Windows.RoutedEventArgs args) + 0x73 байт
PresentationCore.dll! System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) + 0x3d байт
PresentationCore.dll! System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x40 байт
PresentationCore.dll! System.Windows.Input.InputManager.ProcessStagingArea() + 0x1f8 байт
PresentationCore.dll! System.Windows.Input.InputManager.ProcessInput(вход System.Windows.Input.InputEventArgs) + 0x45 байт PresentationCore.dll! System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) + 0x62 байт
PresentationCore.dll! System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawKeyboardActions action, int scanCode, bool isExtendedKey, bool isSystemKey, int virtualKey) + 0xee байт PresentationCore.dll! System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(ref System.Windows.Interop.MSG msg, ref bool handled) + 0xac bytes
PresentationCore.dll! System.Windows.Interop.HwndSource.CriticalTranslateAccelerator(ref System.Windows.Interop.MSG msg, Модификаторы System.Windows.Input.ModifierKeys) + 0x94 байт
PresentationCore.dll! System.Windows.Interop.HwndSource.OnPreprocessMessage(параметр объекта) + 0x12c байт
WindowsBase.dll! System.Windows.Threading.ExceptionWrapper.InternalRealCall(обратный вызов System.Delegate, object args, int numArgs) + 0x56 байт WindowsBase.dll! MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(источник объекта, метод System.Delegate, object args, int numArgs, System.Delegate catchHandler) + 0x3a байт
WindowsBase.dll! System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate, object args, int numArgs) + 0x10e байт WindowsBase.dll! System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority priority, System.Delegate method, object arg) + 0x3e байты
PresentationCore.dll! System.Windows.Interop.HwndSource.OnPreprocessMessageThunk(ref System.Windows.Interop.MSG msg, ref bool обработано) + 0x93 байт
PresentationCore.dll! System.Windows.Interop.HwndSource.WeakEventPreprocessMessage.OnPreprocessMessage(ref System.Windows.Interop.MSG msg, ref bool обработано) + 0x33 байт
WindowsBase.dll! System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage(ref System.Windows.Interop.MSG msg) + 0x3c байты
WindowsBase.dll! System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame) + 0x9a байт
WindowsBase.dll! System.Windows.Threading.Dispatcher.PushFrame(файл System.Windows.Threading.DispatcherFrame) + 0x49 байт
WindowsBase.dll! System.Windows.Threading.Dispatcher.Run() + 0x4b байт
PresentationFramework.dll! System.Windows.Application.RunDispatcher(игнорирование объекта) + 0x17 байт
PresentationFramework.dll! System.Windows.Application.RunInternal(окно System.Windows.Window) + 0x6f байт PresentationFramework.dll! System.Windows.Application.Run(окно System.Windows.Window) + 0x26 байт PresentationFramework.dll! System.Windows.Application.Run() + 0x1b байт WpfApplication1.exe! WpfApplication1.App.Main() + 0x59 байтов С# Переход к управляемому переходному процессу
[Управляемый для коренного перехода]
mscorlib.dll! System.AppDomain.ExecuteAssembly(строка assemblyFile, System.Security.Policy.Evidence assemblySecurity, string [] args) + 0x6b байт
Microsoft.VisualStudio.HostingProcess.Utilities.dll! Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 байт
mscorlib.dll! System.Threading.ThreadHelper.ThreadStart_Context (состояние объекта) + 0x6f байт
mscorlib.dll! System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executeContext, System.Threading.ContextCallback callback, состояние объекта, bool preserveSyncCtx) + 0xa7 байт
mscorlib.dll! System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executeContext, System.Threading.ContextCallback callback, состояние объекта, bool preserveSyncCtx) + 0x16 байт
mscorlib.dll! System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executeContext, System.Threading.ContextCallback callback, состояние объекта) + 0x41 байт
mscorlib.dll! System.Threading.ThreadHelper.ThreadStart() + 0x44 байт
[Отправлено к управляемому переходному процессу]
Ответ 3
Попробуйте следующее:
-
Записать конвертер
public class NullToItemConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return new Item();
else
return value;
}
}
-
в XAML
<Window.Resources>
<local:NullToItemConverter x:Key="nullToItemConverter"/>
</Window.Resources
...
<ComboBox IsEditable="True"
VerticalAlignment="Top"
ItemsSource="{Binding Items}"
DisplayMemberPath="Name"
SelectedItem="{Binding Item, Mode=TwoWay , Converter={StaticResource nullToItemConverter}}"/>