2013-07-18 72 views
16

我現在對組合框有點沮喪,並且希望有人對我的問題有一個答案。問題出在SelectedItem上。當我在調試器中運行我的應用程序時,如果我在項目中輸入與項目(即.. a,b或c)匹配的組合框中的文本,然後刪除文本,它將引發空引用異常。如果我在ComboBox中輸入文本並且與項目中的項目(即.. z)不匹配,然後刪除文本,則不會崩潰。這種行爲只發生在調試器中。如果我在外面運行應用程序,我不會崩潰。我正在使用mvvmlight grabit,但我並不認爲它與此有關。我的代碼如下Combobox SelectedItem DataBinding NullReference異常

查看:

<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'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); 
     } 
    } 
+0

當你說你正在輸入和刪除項目時,你能解釋多一點你指的是什麼嗎?這是在用戶界面?或者在代碼中?要麼...? – Tim

+1

當我在調試器中運行應用程序時,ComboBox屬性IsEditable =「True」。因此,我可以添加和刪除組合框中的文本。對不起,我會編輯以清楚說明。 – poco

+1

乍一看,你的代碼看起來很完美,應該一次運行。所以我試了一下,它按預期工作。所以你提供的代碼沒有問題。 – Nitesh

回答

23

這是在.NET中的錯誤Framework 4的(和.NET 4.5,不是在.NET 3.0和.NET 3.5 )。

方法PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid(object item)導致此問題。

與.net反射來看,其代碼如下所示:

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發生的地方,因爲argsnull,因爲屬性不是索引器。它恰好被命名爲"Item"

.NET實施者應該在info上使用PropertyInfo.GetIndexParameters(),並且如果返回的數組不包含零元素,請確定屬性是索引器。或者使用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之外失敗的原因。

,可以有以下選擇擺脫這個問題:

  1. 重命名這勢必ComboBox.SelectedItem"Item",使車.NET實現已經不認爲屬性是索引一些其他的name屬性。
  2. 從項目引用中刪除System.Data.dll,因此即使在Visual Studio調試器中也不會加載它。

我發現選項2更加脆弱,因爲可能會出現System.Data.dll必須直接由您的應用程序加載或由其他加載程序集間接加載的情況。

所以我會選擇1.

+2

確認這兩個選項都如上所述工作 - 在針對.NET 4.5的VS2012上進行了測試。好工作@Stipo並感謝分享!這個故事的寓意 - **從不**將您的任何視圖模型的屬性命名爲「** Item **」:) – Sevenate

3

我能重現此在我身邊。添加到您的組合框代碼:

IsTextSearchEnabled="False" 

不管怎麼說,還有誰關心這個問題,此異常堆棧跟蹤如下:

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!系統.Windows.Data.BindingExpressionBase.UpdateValue()+ 0x92 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateOverride()+ 0x3d bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Update() + 0x20 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.ProcessDirty()+ 0x2f bytes PresentationFramework.dll!System.Windows.Data.BindingExpress ()+ 0x40字節
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.SetValue(System.Windows.DependencyObject d,System.Windows.DependencyProperty dp,object value)+ 0x24 bytes
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,object value)+ 0x35 bytes
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.UpdatePublicSelectionProperties()+ 0x13f by tes
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.SelectionChanger。完()+ 0x80的字節
PresentationFramework.dll!System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(System.Windows.Controls.ItemsControl.ItemInfo信息,布爾assumeInItemsCollection)+ 0x145字節
PresentationFramework.dll!系統.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 bytes
WindowsBase.dll!System.Windows .DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args)+ 0x3b bytes
WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex,System.Windows.DependencyProperty dp,System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry,ref System.Windows.EffectiveValueEntry newEntry,bool coerceWithDeferredReference,bool coerceWithCurrentValue,System.Windows.OperationType operationType)+ 0x757 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp,對象值,System.Windows.PropertyMetadata元數據,bool coerceWithDeferredReference,bool coerceWithCurrentValue,System.Windows.OperationType operationType,bool isInternal)+ 0x2ea字節
WindowsBa se.dll!System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty dp,object value)+ 0x35 bytes
PresentationFramework.dll!System.Windows.Controls.ComboBox.TextUpdated(string newText,bool textBoxUpdated)+ 0x26e bytes
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 bytes
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler,object target)+ 0x33 bytes
PresentationCore.dll!System.W indows.RoutedEventHandlerInfo.InvokeHandler(對象目標,System.Windows.RoutedEventArgs routedEventArgs)+ 0×44字節
PresentationCore.dll中!System.Windows.EventRoute.InvokeHandlersImpl(對象源,System.Windows.RoutedEventArgs指定參數時,布爾再加註)+ 0x1a8字節
(System.Windows.RoutedEventArgs args)+ 0x73字節
PresentationCore.dll! )+ 0x29 bytes PresentationFramework.dll!System.Windows.Controls.Primitives.TextBoxBase.OnTextChanged(System.Windows.Controls.TextChangedEventArgs e)+ 0x5 bytes
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 bytes
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 bytes PresentationFramework.dll!System.Windows.Documents。TextRange.System.Windows.Documents.ITextRange.EndChange(布爾disableScroll,布爾skipEvents)+ 0×11字節
PresentationFramework.dll!System.Windows.Documents.TextRange.ChangeBlock.System.IDisposable.Dispose()+ 0×15字節
PresentationFramework .dll!System.Windows.Documents.TextEditorTyping.OnDelete(object sender,System.Windows.Input.ExecutedRoutedEventArgs args)+ 0x1a7 bytes
PresentationCore.dll!System.Windows.Input.CommandBinding.OnExecuted(object sender,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,object sender,System.Windows.RoutedEventArgs e,System.Windows.Input.ICommand command,bool execute)+ 0x105 bytes
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(對象發件人,System.Windows.Input.ExecutedRoutedEventArgs E)+ 0x25字節 PresentationCore.dll中!System.Windows.UIElement.OnExecutedThunk(對象發件人,System.Windows.Input.ExecutedRoutedEventArgs E)+ 0×46字節
PresentationCore.dll中!System.Windows.Input.ExecutedRoutedEventArgs.Invok eEventHandler(System.Delegate genericHandler,對象目標)+字節爲0x3C
PresentationCore.dll中!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate處理程序,對象目標)+ 0x33字節
PresentationCore.dll中!System.Windows.RoutedEventHandlerInfo。 InvokeHandler(對象目標,System.Windows.RoutedEventArgs routedEventArgs)+ 0×44字節
PresentationCore.dll中!System.Windows.EventRoute.InvokeHandlersImpl(對象源,System.Windows.RoutedEventArgs指定參數時,布爾再加註)+ 0x1a8字節
PresentationCore.dll中!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender,System.Windows.RoutedEventArgs args)+ 0x73 bytes
PresentationCore.dll!System.Windows.UIElement.Rais eTrustedEvent(System.Windows.RoutedEventArgs參數)+ 0x3D之間字節
PresentationCore.dll中!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs指定參數時,布爾信任)+ 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 bytes PresentationCore.dll!System.Windows.Input.CommandManager.TranslateInput(System.Windows.IInputElement targetElement,System.Windows.Input.InputEventArgs inputEventArgs)+ 0x59b bytes
PresentationCore.dll!System.Windows.UIE lement.OnKeyDownThunk(對象發件人,System.Windows.Input.KeyEventArgs E)+ 0×52字節
PresentationCore.dll中!System.Windows.Input.KeyEventArgs.InvokeEventHandler(System.Delegate genericHandler,對象genericTarget)+ 0x2c上字節
PresentationCore。 DLL!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate處理程序,對象目標)+ 0x33字節
PresentationCore.dll中!System.Windows.RoutedEventHandlerInfo.InvokeHandler(對象目標,System.Windows.RoutedEventArgs routedEventArgs)+ 0×44字節
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(對象源,System.Windows.RoutedEventArgs參數,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中!系統.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs指定參數時,布爾信任)+ 0x40的字節
PresentationCore.dll中!System.Windows.Input.InputManager.ProcessStagingArea()+ 0x1f8字節
PresentationCore.dll中!System.Windows。 Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input)+ 0x45 bytes PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport)+ 0x62 bytes
PresentationCore.dll!System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(System.IntPtr hwnd,System.Windows.Input.InputMode mode,int timestamp,System.Windows.Input.RawKeyboardActions actions,int scanCode,bool isExtendedKey,bool isSystemKey, int virtualKey)+ 0xee bytes 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(參考System.Windows.Interop.MSG味精,System.Windows.Input.ModifierKeys改性劑)+ 0x94之間的字節
PresentationCore.dll中!System.Windows.Interop.HwndSource.OnPreprocessMessage(對象PARAM)+ 0x12c字節
WindowsBase.dll中!System.Windows.Thr eading.ExceptionWrapper.InternalRealCall(System.Delegate回調,object args,int numArgs)+ 0x56 bytes WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object source,System.Delegate方法,object args,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 priority,System.Delegate method,object arg)+ 0x3e bytes
PresentationCore.dll!System.Windows.Interop.HwndSource。 OnPreprocessMessageThunk(ref System.Windows.Interop.MSG msg,ref bool handling)+ 0x93 bytes
PresentationCore.dll中!System.Windows.Interop.HwndSource.WeakEventPreprocessMessage.OnPreprocessMessage(參照System.Windows.Interop.MSG MSG,參考布爾處理)+ 0x33字節
WindowsBase.dll中!System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage (ref System.Windows.Interop.MSG msg)+ 0x3c bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame)+ 0x9a bytes
WindowsBase.dll!System。 Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame)+ 0x49 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.Run()+ 0x4b bytes
Present ationFramework.dll!System.Windows.Application.RunDispatcher(object ignore)+ 0x17 bytes
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window)+ 0x6f bytes PresentationFramework.dll!System.Windows .Application.Run(System.Windows.Window window)+ 0x26 bytes PresentationFramework.dll!System.Windows.Application.Run()+ 0x1b bytes WpfApplication1.exe!WpfApplication1.App.Main()+ 0x59 bytes C# [原生到託管轉換]
[託管到本地轉換]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile,System.Security.Policy。證據assemblySecurity,串[]參數)+ 0x6b字節
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()+ 0×27字節
mscorlib.dll中!System.Threading.ThreadHelper.ThreadStart_Context (對象狀態)+ 0x6f字節
mscorlib.dll中!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext的ExecutionContext,System.Threading.ContextCallback回調,對象的狀態,布爾preserveSyncCtx)+ 0xa7字節
mscorlib.dll中! System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallback callback,object state,bool preserveSyncCtx)+ 0x16 bytes
mscorlib.dll!Sys tem.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallback callback,object state)+ 0x41 bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()+ 0x44 bytes
[Native以管理轉型]

+0

感謝您花時間看這個。將此設置爲False可以停止崩潰,但是,這也需要您從ComboBox中選擇一個項目來更新SelectedItem綁定,而不是僅僅能夠輸入它。就像我之前所說的,如果在沒有調試器的情況下運行它,按預期工作。一直對此行爲尖刻,希望有人能給我這個原因。 – poco

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}}"/> 
    
+0

感謝您花時間看這個。我明白這將會阻止這場事故。但是,這將視圖模型中的Item作爲新項目。沒有理由我可以看到Item不應該被設置爲null。就像我上面所說的那樣,如果你在沒有調試的情況下運行,你將不會遇到崩潰。我對這種情況發生的原因感興趣,而不是真正的解決方法。 – poco