CommunityToolkit / CommunityToolkit/dotnet
Crash when command parameter is MS.Internal.NamedObject "DisconnectedItem"
- Dominant language
- C#
- Stars
- 3.8k
- Forks
- 400
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the bug
I have a contextmenu with one option "Move To" with some dynamically added sub-menuitems "destinations", which are create by binding the itemsource of the top menu item to an observableCollection of strings. All of these sub-menuitems share the same Command, and pass their header as the command parameter.
The first time I open the context menu and chose a destination, everything works fine. The second time you open the context menu however, the application crashes with the following error.
```
{"Parameter \"parameter\" (object) cannot be of type MS.Internal.NamedObject, as the command type requires an argument of type System.String. (Parameter 'parameter')"}
```
By putting a value converter on the command parameter binding and putting a breakpoint inside, I could inspect the problematic parameter and it is a `MS.Internal.NamedObject`, with name `DisconnectedItem`.
The only info I could find is this https://learn.microsoft.com/en-us/archive/msdn-technet-forums/36aec363-9e33-45bd-81f0-1325a735cc45 and this https://stackoverflow.com/questions/3868786/wpf-sentinel-objects-and-how-to-check-for-an-internal-type.
Stacktrace:
```
at CommunityToolkit.Mvvm.Input.RelayCommand`1.ThrowArgumentExceptionForInvalidCommandArgument(Object parameter)
at CommunityToolkit.Mvvm.Input.RelayCommand`1.CanExecute(Object parameter)
at System.Windows.Controls.MenuItem.UpdateCanExecute()
at System.Windows.Controls.MenuItem.OnCommandChanged(ICommand oldCommand, ICommand newCommand)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.PropertyPathWorker.OnDependencyPropertyChanged(DependencyObject d, DependencyProperty dp, Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.OnPropertyInvalidation(DependencyObject d, DependencyPropertyChangedEventArgs args)
at System.Windows.DependentList.InvalidateDependents(DependencyObject source, DependencyPropertyChangedEventArgs sourceArgs)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.TreeWalkHelper.InvalidateTreeDependentProperty(TreeChangeInfo info, DependencyObject d, FrameworkObject& fo, DependencyProperty dp, FrameworkPropertyMetadata fMetadata, Style selfStyle, Style selfThemeStyle, ChildRecord& childRecord, Boolean isChildRecordValid, Boolean hasStyleChanged, Boolean isSelfInheritanceParent, Boolean wasSelfInheritanceParent)
at System.Windows.TreeWalkHelper.InvalidateTreeDependentProperties(TreeChangeInfo info, FrameworkElement fe, FrameworkContentElement fce, Style selfStyle, Style selfThemeStyle, ChildRecord& childRecord, Boolean isChildRecordValid, Boolean hasStyleChanged, Boolean isSelfInheritanceParent, Boolean wasSelfInheritanceParent)
at System.Windows.FrameworkElement.InvalidateTreeDependentProperties(TreeChangeInfo parentTreeState, Boolean isSelfInheritanceParent, Boolean wasSelfInheritanceParent)
at System.Windows.FrameworkElement.OnAncestorChangedInternal(TreeChangeInfo parentTreeState)
at System.Windows.TreeWalkHelper.OnAncestorChanged(DependencyObject d, TreeChangeInfo info, Boolean visitedViaVisualTree)
at MS.Internal.PrePostDescendentsWalker`1._VisitNode(DependencyObject d, Boolean visitedViaVisualTree)
at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)
at System.Windows.DescendentsWalker`1.WalkFrameworkElementLogicalThenVisualChildren(FrameworkElement feParent, Boolean hasLogicalChildren)
at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)
at MS.Internal.PrePostDescendentsWalker`1._VisitNode(DependencyObject d, Boolean visitedViaVisualTree)
at System.Windows.DescendentsWalker`1.WalkLogicalChildren(FrameworkElement feParent, FrameworkContentElement fceParent, IEnumerator logicalChildren)
at System.Windows.DescendentsWalker`1.WalkFrameworkElementLogicalThenVisualChildren(FrameworkElement feParent, Boolean hasLogicalChildren)
at System.Windows.DescendentsWalker`1.IterateChildren(DependencyObject d)
at System.Windows.DescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode)
at MS.Internal.PrePostDescendentsWalker`1.StartWalk(DependencyObject startNode, Boolean skipStartNode)
at System.Windows.TreeWalkHelper.InvalidateOnTreeChange(FrameworkElement fe, FrameworkContentElement fce, DependencyObject parent, Boolean isAddOperation)
at System.Windows.Controls.Primitives.Popup.CreateWindow(Boolean asyncCall)
at System.Windows.Controls.Primitives.Popup.OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.PropertyPathWorker.OnDependencyPropertyChanged(DependencyObject d, DependencyProperty dp, Boolean isASubPropertyChange)
at System.Windows.Data.BindingExpression.OnPropertyInvalidation(DependencyObject d, DependencyPropertyChangedEventArgs args)
at System.Windows.DependentList.InvalidateDependents(DependencyObject source, DependencyPropertyChangedEventArgs sourceArgs)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at CrashOnDisconnectedItem.MainWindow.Button_Click(Object sender, RoutedEventArgs e) in C:\Users\pauld\Documents\dev\CrashOnDisconnectedItem\CrashOnDisconnectedItem\MainWindow.xaml.cs:line 23
```
### Regression
_No response_
### Steps to reproduce
I made a minimal repo to reproduce the crash https://github.com/DSPaul/CrashOnDisconnectedItem.
Simply click the button and chose a destination option, you will see a messagebox showing that it works. Click the btn again, you will see another messagebox showing the exception because it crashed.
The repo consists of these 3 simple files:
MainWindow.xaml
``` xaml
<Setter Property="MenuItem.Command" Value="{Binding Path=DataContext.MoveCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}"/>
<Setter Property="MenuItem.CommandParameter" Value="{Binding Header, RelativeSource={RelativeSource self}}"/>
```
MainWindow.xaml.cs
``` cs
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new MainViewModel();
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
Button btn = (Button)sender;
btn.ContextMenu!.PlacementTarget = btn;
btn.ContextMenu!.IsOpen = !btn.ContextMenu!.IsOpen;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "crash", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
```
MainViewModel
``` cs
public partial class MainViewModel
{
public ObservableCollection Destinations { get; } = ["loc1", "loc2", "loc3"];
[RelayCommand]
public void Move(string? destination)
{
if (string.IsNullOrEmpty(destination))
{
throw new ArgumentNullException(nameof(destination));
}
//do something here
MessageBox.Show($"Moved something to {destination}");
}
}
```
### Expected behavior
Definitely not crash, when CanExcecute is called with DisconnectedItem as parameter, it should probably just return false.
### Screenshots
_No response_
### IDE and version
VS 2022
### IDE version
Version 17.9.1
### Nuget packages
- [ ] CommunityToolkit.Common
- [ ] CommunityToolkit.Diagnostics
- [ ] CommunityToolkit.HighPerformance
- [X] CommunityToolkit.Mvvm (aka MVVM Toolkit)
### Nuget package version(s)
8.2.2
### Additional context
_No response_
### Help us help you
No, just wanted to report this
Contributor guide
Assessment
This issue has not been assessed yet.