19

I am a bit frustrated with combobox right now and am hoping someone has an answer for my question. The problem is with SelectedItem. When i run my app in debugger it will throw a null reference exception if I enter text into the ComboBox that matchs an Item(ie.. a, b, or c) in Items, and then delete the text. If i enter text into the ComboBox and that does not match and Item(ie.. z) in Items and then delete the text, it does not crash. This behavior only happens within the debugger. If I run the application outside I do not crash. I'm using the mvvmlight tookit however i'm not thinking it has anything to do with that. My code is below

View:

<ComboBox IsEditable="True"
              VerticalAlignment="Top"
              ItemsSource="{Binding Items}"
              DisplayMemberPath="Name"
              SelectedItem="{Binding Item,Mode=TwoWay}"/>

Model:

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's name.
    /// </summary>
    public const string ItemsPropertyName = "Items";

    private List<Item> _items;

    /// <summary>
    /// Sets and gets the Items property.
    /// Changes to that property's 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's name.
    /// </summary>
    public const string ItemPropertyName = "Item";

    private Item _item;

    /// <summary>
    /// Sets and gets the Item property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public Item Item
    {
        get
        {
            return _item;
        }
        set
        {
            Set(ItemPropertyName, ref _item, value);
        }
    }
4

4 回答 4

30

这是 .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;

代码假设 if columnNameis "Item",则 property 是 indexer 并尝试通过它访问其第一个参数args[0],这是NullReferenceException发生的地方,因为argsisnull因为 property 不是 indexer。它恰好被命名为"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变量不会为空(它实际上是持有实例的WeakReferenceMainViewModel的实例),因此调用失败方法的唯一条件DetermineWhetherDBNullIsValid(item)是是否加载了 System.Data.dll 程序集,并使用AssemblyHelper.IsLoaded(UncommonAssembly.System_Data).

Visual Studio 调试器将始终加载 System.Data.dll,因为项目正在引用它,尽管它没有使用它。在 Visual Studio 调试器之外,System.Data.dll 仅在使用时才被加载,这是永远不会的,这就是应用程序在 Visual Studio 之外不会失败的原因。

您有以下选项可以解决此问题:

  1. 重命名绑定到ComboBox.SelectedItem某个名称的属性,而不是"Item"让有缺陷的 .NET 实现不再假定该属性是索引器。
  2. 从项目引用中删除 System.Data.dll,这样即使在 Visual Studio 调试器中也不会加载它。

我发现选项 2 更脆弱,因为可能会出现 System.Data.dll 必须加载的情况,要么直接由您的应用程序加载,要么由其他加载的程序集间接加载。

所以我会选择选项1。

于 2013-07-23T20:57:09.533 回答
4

我能够在我这边重现这个。将此添加到您的组合框代码中:

IsTextSearchEnabled="False"

无论如何,还有谁对这个问题感兴趣,这个异常的堆栈跟踪如下

PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid(object item) + 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 字节
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 assumeInItemsCollection) + 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 字节
WindowsBase.dll!System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp, 对象值) + 0x35 字节
PresentationFramework.dll!System.Windows.Controls.ComboBox.TextUpdated(string newText, bool textBoxUpdated) + 0x26e 字节
PresentationFramework。 dll!System.Windows.Controls.ComboBox.OnEditableTextBoxTextChanged(object sender, 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(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x44 bytes
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1a8 字节
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject 发送者,System.Windows.RoutedEventArgs 参数) + 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(object sender, System.Windows.Documents.TextContainerChangedEventArgs e) + 0xe0 字节
PresentationFramework.dll!System.Windows.Controls.TextBox.OnTextContainerChanged(object sender, 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(object sender, System.Windows.Input.ExecutedRoutedEventArgs args) + 0x1a7 字节
PresentationCore.dll!System.Windows.Input.CommandBinding.OnExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x65 bytes PresentationCore.dll!System.Windows.Input.CommandManager.ExecuteCommandBinding(object sender, System.Windows. Input.ExecutedRoutedEventArgs e, System.Windows.Input.CommandBinding commandBinding) + 0x92 字节
PresentationCore.dll!System.Windows.Input.CommandManager.FindCommandBinding(System.Windows.Input.CommandBindingCollection commandBindings, object sender, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand 命令,bool 执行)+ 0x105 字节
PresentationCore.dll!System.Windows.Input.CommandManager.FindCommandBinding(object sender, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand command, bool execute) + 0x15e bytes PresentationCore.dll!System.Windows.Input.CommandManager .OnExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x25 bytes PresentationCore.dll!System.Windows.UIElement.OnExecutedThunk(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x46 bytes
PresentationCore.dll!System .Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(System.Delegate genericHandler, object target) + 0x3c bytes
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x33 bytes
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x44 bytes
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1a8 字节
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject 发送方,System.Windows.RoutedEventArgs 参数)+ 0x73 字节
PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs 参数) + 0x3d 字节
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trust) + 0x40 字节
PresentationCore.dll!System.Windows.Input.RoutedCommand.ExecuteImpl(object parameter, System.Windows.IInputElement target, bool userInitiated) + 0x105 bytes
PresentationCore.dll!System.Windows.Input.RoutedCommand.ExecuteCore(object parameter, 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(object sender, 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(对象目标,System.Windows.RoutedEventArgs routedEventArgs)+ 0x44 字节
PresentationCore。 dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0x1a8 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, 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 trust) + 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 模式, int 时间戳, System.Windows.Input.RawKeyboardActions 动作, int scanCode, bool isExtendedKey, bool isSystemKey, int virtualKey) + 0xee 字节 PresentationCore.dll!System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(ref System.Windows.Interop.MSG msg, ref bool 处理) + 0xac 字节
PresentationCore.dll!System.Windows.Interop.HwndSource.CriticalTranslateAccelerator(参考 System.Windows.Interop.MSG 消息,System.Windows.Input.ModifierKeys 修饰符)+ 0x94 字节
PresentationCore.dll!System.Windows.Interop.HwndSource.OnPreprocessMessage(对象参数)+ 0x12c 字节
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) + 0x56 bytes WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object source, System.Delegate method,对象参数,int numArgs,System.Delegate catchHandler) + 0x3a 字节
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority 优先级,System.TimeSpan 超时,System.Delegate 方法,对象参数, int numArgs) + 0x10e 字节 WindowsBase.dll!System.Windows.Threading.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority 优先级,System.Delegate 方法,对象 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 消息,ref bool 处理)+ 0x33 字节
WindowsBase.dll!System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage(参考 System.Windows.Interop.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 bytes C# [Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string 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 executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0xa7 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading. ContextCallback 回调,对象状态,bool preserveSyncCtx) + 0x16 字节
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x41 bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes
[Native到托管过渡]

于 2013-07-20T22:28:47.290 回答
3

尝试这个:

  1. 写一个转换器

    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;
        }
    }
    
  2. 在 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}}"/>
    
于 2013-07-22T19:15:46.853 回答
0

我通过公开访问修饰符解决了这个问题,以便它可以以双向绑定。

于 2021-05-30T08:07:42.943 回答