19

私は現在、コンボボックスに少し不満を感じており、誰かが私の質問に答えてくれることを望んでいます。問題は SelectedItem にあります。デバッガーでアプリを実行すると、アイテムのアイテム (つまり、a、b、または c) に一致するテキストを ComboBox に入力し、テキストを削除すると、null 参照例外がスローされます。ComboBox にテキストを入力し、それが一致せず、Items の Item(ie.. z) になってからテキストを削除しても、クラッシュしません。この動作は、デバッガー内でのみ発生します。アプリケーションを外部で実行しても、クラッシュしません。私は 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; }
}

仮想マシン:

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 3.0 と .NET 3.5 ではなく、 .NET 4.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コードは、 isの場合、 property はインデクサーであると想定し"Item"、最初の引数を介してアクセスしようとします。これは、プロパティがインデクサーではないためargs[0]、 is がNullReferenceException発生する場所です。たまたま名前が付けられただけです。argsnull"Item"

.NET の実装者は、PropertyInfo.GetIndexParameters()を onで使用する必要がinfoあり、返された配列にゼロ要素が含まれていない場合は、プロパティがインデクサーであると特定の想定をしてください。または、チェックにBinding.IndexerNameを使用します (Binding.IndexerName には value があります"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);
}

variable は null にならないためitem(実際には、インスタンスを保持するWeakReferenceMainViewModelのインスタンスです)、失敗したメソッドが呼び出される唯一の条件DetermineWhetherDBNullIsValid(item)は、System.Data.dll アセンブリが読み込まれている場合であり、これは でチェックされAssemblyHelper.IsLoaded(UncommonAssembly.System_Data)ます。

Visual Studio デバッガーは常に System.Data.dll を読み込みます。これは、プロジェクトが System.Data.dll を使用していなくても参照しているためです。Visual Studio デバッガーの外部では、System.Data.dll は使用された場合にのみ読み込まれますが、決して読み込まれることはありません。そのため、Visual Studio の外部でアプリケーションが失敗することはありません。

この問題を解決するには、次のオプションがあります。

  1. バグのある .NET 実装がそのプロパティがインデクサーであると想定しないように、ComboBox.SelectedItem別の名前にバインドされているプロパティの名前を変更します。"Item"
  2. プロジェクト参照から System.Data.dll を削除して、Visual Studio デバッガーでも読み込まれないようにします。

System.Data.dll をアプリケーションによって直接、または他のロードされたアセンブリによって間接的にロードする必要がある状況が発生する可能性があるため、オプション 2 はより壊れやすいと思います。

したがって、私はオプション 1 を使用します。

于 2013-07-23T20:57:09.533 に答える
4

私はこれを私の側で再現できます。これをコンボボックス コードに追加します。

IsTextSearchEnabled="False"

とにかく、この問題に興味がある人は、この例外のスタックトレースは次のとおりです

PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid(オブジェクト項目) + 0xc7 バイトPresentationFramework.dll !
MS.Internal.Data.PropertyPathWorker.DetermineWhetherDBNullIsValid() + 0x64 バイト
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, object value) + 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, object value) + 0x35 バイト
PresentationFramework.dll!System.Windows.Controls.ComboBox.TextUpdated(string 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、オブジェクト 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(オブジェクト ソース、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 引数) + 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 コマンド、bool execute) + 0x105 バイト
PresentationCore.dll!System.Windows.Input.CommandManager.FindCommandBinding(オブジェクト送信者、System.Windows.RoutedEventArgs e、System.Windows.Input.ICommand コマンド、bool 実行) + 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(オブジェクト ターゲット、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、オブジェクト 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(オブジェクト ソース、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 入力レポート) + 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 メッセージ、ref bool 処理) + 0xac バイト
PresentationCore.dll!System.Windows.Interop.HwndSource.CriticalTranslateAccelerator( ref 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 コールバック、オブジェクト引数、int numArgs) + 0x56 バイト WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(オブジェクト ソース、System.Delegate メソッド、オブジェクト引数、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 メソッド、オブジェクト引数) + 0x3e バイト
PresentationCore.dll!System.Windows.Interop.HwndSource.OnPreprocessMessageThunk(ref System.Windows.Interop.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 バイト C# [ネイティブからマネージドへの移行]
[マネージドからネイティブへの移行]
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 コールバック、オブジェクト状態、bool preserveSyncCtx) + 0xa7 バイト
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 コールバック、オブジェクト状態) + 0x41 バイト
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 バイト
[ネイティブ管理された移行へ]

于 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 に答える