Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Value cannot be null. Parameter name: key (only happens on XAML Designer's design view)

XAML Designer design view shows

An Exception was thrown

ArgumentNullException: Value cannot be null.

Parameter name: key

StackTrace (see after photo)

InnerException: None

I have been struggling for few days on the following issue, which prevents me from using XAML Designer's design view on every affected view.

Yesterday, I eventually managed to isolate this odd behaviour which it particulary hard to trace, since it happens only at design-time, and that seems a conflit between generic type and DataGrid's ItemsSource property (System.Windows.Controls).

So, this is what is shown on the design view

enter image description here

at System.Collections.Generic.Dictionary2.FindEntry(TKey key) at System.Collections.Generic.Dictionary2.TryGetValue(TKey key, TValue& value) at System.Windows.Controls.DataGridItemAttachedStorage.TryGetValue(Object item, DependencyProperty property, Object& value) at System.Windows.Controls.DataGridRow.RestoreAttachedItemValue(DependencyObject objectWithProperty, DependencyProperty property) at System.Windows.Controls.DataGridRow.SyncProperties(Boolean forcePrepareCells) at System.Windows.Controls.DataGridRow.PrepareRow(Object item, DataGrid owningDataGrid) at System.Windows.Controls.DataGrid.PrepareContainerForItemOverride(DependencyObject element, Object item) at System.Windows.Controls.ItemsControl.MS.Internal.Controls.IGeneratorHost.PrepareItemContainer(DependencyObject container, Object item) at System.Windows.Controls.ItemContainerGenerator.System.Windows.Controls.Primitives.IItemContainerGenerator.PrepareItemContainer(DependencyObject container) at System.Windows.Controls.VirtualizingStackPanel.InsertContainer(Int32 childIndex, UIElement container, Boolean isRecycled) at System.Windows.Controls.VirtualizingStackPanel.AddContainerFromGenerator(Int32 childIndex, UIElement child, Boolean newlyRealized, Boolean isBeforeViewport) at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(IItemContainerGenerator& generator, IContainItemStorage& itemStorageProvider, IContainItemStorage& parentItemStorageProvider, Object& parentItem, Boolean& hasUniformOrAverageContainerSizeBeenSet, Double& computedUniformOrAverageContainerSize, Double& computedUniformOrAverageContainerPixelSize, Boolean& computedAreContainersUniformlySized, IList& items, Object& item, IList& children, Int32& childIndex, Boolean& visualOrderChanged, Boolean& isHorizontal, Size& childConstraint, Rect& viewport, VirtualizationCacheLength& cacheSize, VirtualizationCacheLengthUnit& cacheUnit, Boolean& foundFirstItemInViewport, Double& firstItemInViewportOffset, Size& stackPixelSize, Size& stackPixelSizeInViewport, Size& stackPixelSizeInCacheBeforeViewport, Size& stackPixelSizeInCacheAfterViewport, Size& stackLogicalSize, Size& stackLogicalSizeInViewport, Size& stackLogicalSizeInCacheBeforeViewport, Size& stackLogicalSizeInCacheAfterViewport, Boolean& mustDisableVirtualization, Boolean isBeforeFirstItem, Boolean isAfterFirstItem, Boolean isAfterLastItem, Boolean skipActualMeasure, Boolean skipGeneration, Boolean& hasBringIntoViewContainerBeenMeasured, Boolean& hasVirtualizingChildren) at System.Windows.Controls.VirtualizingStackPanel.MeasureOverrideImpl(Size constraint, Nullable1& lastPageSafeOffset, List1& previouslyMeasuredOffsets, Nullable`1& lastPagePixelSize, Boolean remeasure) at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint) at System.Windows.Controls.Primitives.DataGridRowsPresenter.MeasureOverride(Size constraint) at System.Windows.FrameworkElement.MeasureCore(Size availableSize) at System.Windows.UIElement.Measure(Size availableSize) at System.Windows.ContextLayoutManager.UpdateLayout() at System.Windows.UIElement.UpdateLayout()

Sample project source code

MyViewModelbase.cs (this is my generic view model base)

namespace BugProof.ViewModels
{
    using System.Collections.Generic;

    public class MyViewModelBase<TItem> where TItem : class
    {
        public List<TItem> Items { get; set; }
        public MyViewModelBase() { }
    }
}

MyExtendedViewModel.cs (this my extended view model, which will be based upon a string type)

namespace BugProof.ViewModels
{
    public class MyExtendedViewModel : MyViewModelBase<string>
    {
        public MyExtendedViewModel()
        {
        }
    }
}

MainWindow.xaml

<Window x:Class="BugProof.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:BugProof.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BugProof"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance {x:Type vm:MyExtendedViewModel}, IsDesignTimeCreatable=False}"                  
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBlock>This is what you should se in the designer</TextBlock>
        <!--Try replacing following DataGrid by a ListBox or ListView-->
        <DataGrid ItemsSource="{Binding Items}"/>
    </StackPanel>
</Window>

MainWindow.xaml.cs (MainWindow's code behind)

using System.Windows;

namespace BugProof
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

Complementary details:

  • The behaviour does not occur if one replaces DataGrid control by a Listbox, ListView or ItemsControl
  • I am using Visual Studio 2015, Version 14.0.25431.01 Update 3
  • Project is targeted to .Net Framework 4.5
like image 950
Julio Nobre Avatar asked Mar 15 '17 13:03

Julio Nobre


2 Answers

Setting IsDesignTimeCreatable=True on MainWindows.xaml did the trick, although it requires special care implementing view model's parameters-less constructor, checking whether code is running in design-time or not.

According to Microsoft, setting IsDesignTimeCreatable=True, "specifies that the design instance is created from your type, instead of a designer-generated substitute type".

Surprisingly, also according to Microsoft, if IsDesignTimeCreatable is not set or set to False, "all the design tool does is parse the class for its bindable properties".

I guess we have got two opposite truths. This may even be the case that both are really true, depending upon context. May be, the second source was not aware, at documentation writing time, the 3 samples that XAML Designer automatically generates once IsDesignTimeCreatable is set to default False value, whenever it finds a collection (IEnumerable) property

Until proof otherwise, this is a WPF DataGrid control bug when ItemsSource is binded to a generic collection source and IsDesignTimeCreatable=False, since this issue does not arise if we replace DataGrid control by ListBox, ListView or ItemsControls.

like image 107
Julio Nobre Avatar answered Nov 15 '22 13:11

Julio Nobre


Fixed this issue with the following:

  1. increased the Designwidth
  2. Revert Designwidth back to original.

FYI I am using Visual Studio 2019.

like image 25
Belcode Avatar answered Nov 15 '22 14:11

Belcode