Item 20216 raised some issues with handling fixed size collection (e.g. arrays). Some changes were made to resolve issues.
Unfortunately there's still issues. Take the following class as the selected object class:
public class Person
{
[Category("Personal Information")]
[DisplayName(@"First Name")]
[Description("The first name or given name.")]
public string FirstName { get; set; }
[Category("Personal Information")]
[DisplayName(@"Last Name")]
[Description("The last name, family name or surname")]
public string LastName { get; set; }
}
public class MarriedPerson : Person
{
[Category("Marriage Information")]
[Description("The spouse personal information.")]
[ExpandableObject]
public Person Spouse { get; set; }
[Category("Marriage Information")]
[Description("The children personal information.")]
public Person[] Children { get; set; }
}
Editing the Children member creates a CollectionControl. If you add some items and then click OK you get the null reference exception:
at Xceed.Wpf.Toolkit.CollectionControl.CreateItemsSource()
at Xceed.Wpf.Toolkit.CollectionControl.ComputeItemsSource()
at Xceed.Wpf.Toolkit.CollectionControl.PersistChanges()
at Xceed.Wpf.Toolkit.CollectionControlDialog.OkButton_Click(Object sender, RoutedEventArgs e)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.TranslateAndDispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Window.ShowHelper(Object booleanBox)
at System.Windows.Window.Show()
at System.Windows.Window.ShowDialog()
at Xceed.Wpf.Toolkit.PropertyGrid.Editors.CollectionEditor.Button_Click(Object sender, RoutedEventArgs e)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.TranslateAndDispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Application.RunInternal(Window window)
at TradeLifeCycleMessageSample.Program.Main(String[] args) in c:\Users\U319813\Documents\Visual Studio 2012\Projects\TradeLifeCycleMessageSample\TradeLifeCycleMessageSample\Program.cs:line 20
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
I have corrected this exception by properly handling creation of arrays in ComputeItemsSource. With that fixed PersistChanges throws because the Items collection is modified after creating the ItemsSource. This occurs because of inconsistent handling of changes in the OnItemSourceChanged method. Correcting this requires changing how the ItemsSource is set otherwise it is not possible to eliminate the changing Items collection after setting up the new ItemsSource and copying items out of it.
Here are the changes I am suggesting to correct these issues:
Change OnItemsSourceChanged to:
public void OnItemSourceChanged(IList oldValue, IList newValue)
{
Items.Clear();
if (newValue != null)
{
foreach (var item in newValue)
Items.Add(item);
}
}
Change CreateItemsSource to:
private IList CreateItemsSource()
{
IList list = null;
if (ItemsSourceType != null)
{
ConstructorInfo constructor = ItemsSourceType.GetConstructor(new[] { typeof(int) });
if (constructor == null)
{
constructor = ItemsSourceType.GetConstructor(Type.EmptyTypes);
if (constructor == null)
{
throw new Exception("No usable constructor to build collection");
}
Change PersistChanges to:
public void PersistChanges()
{
IList list = CreateItemsSource();
if (list == null)
return;
//the easiest way to persist changes to the source is to just clear the source list and then add all items to it.
list.Clear();
if (list.IsFixedSize)
{
for (int i = 0; i < Items.Count; ++i)
list[i] = Items[i];
}
else
{
foreach (var item in Items)
{
list.Add(item);
}
}
ItemsSource = list;
}
and delete ComputeItemsSource.
Unfortunately there's still issues. Take the following class as the selected object class:
public class Person
{
[Category("Personal Information")]
[DisplayName(@"First Name")]
[Description("The first name or given name.")]
public string FirstName { get; set; }
[Category("Personal Information")]
[DisplayName(@"Last Name")]
[Description("The last name, family name or surname")]
public string LastName { get; set; }
}
public class MarriedPerson : Person
{
[Category("Marriage Information")]
[Description("The spouse personal information.")]
[ExpandableObject]
public Person Spouse { get; set; }
[Category("Marriage Information")]
[Description("The children personal information.")]
public Person[] Children { get; set; }
}
Editing the Children member creates a CollectionControl. If you add some items and then click OK you get the null reference exception:
at Xceed.Wpf.Toolkit.CollectionControl.CreateItemsSource()
at Xceed.Wpf.Toolkit.CollectionControl.ComputeItemsSource()
at Xceed.Wpf.Toolkit.CollectionControl.PersistChanges()
at Xceed.Wpf.Toolkit.CollectionControlDialog.OkButton_Click(Object sender, RoutedEventArgs e)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.TranslateAndDispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Window.ShowHelper(Object booleanBox)
at System.Windows.Window.Show()
at System.Windows.Window.ShowDialog()
at Xceed.Wpf.Toolkit.PropertyGrid.Editors.CollectionEditor.Button_Click(Object sender, RoutedEventArgs e)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.TranslateAndDispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Application.RunInternal(Window window)
at TradeLifeCycleMessageSample.Program.Main(String[] args) in c:\Users\U319813\Documents\Visual Studio 2012\Projects\TradeLifeCycleMessageSample\TradeLifeCycleMessageSample\Program.cs:line 20
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
I have corrected this exception by properly handling creation of arrays in ComputeItemsSource. With that fixed PersistChanges throws because the Items collection is modified after creating the ItemsSource. This occurs because of inconsistent handling of changes in the OnItemSourceChanged method. Correcting this requires changing how the ItemsSource is set otherwise it is not possible to eliminate the changing Items collection after setting up the new ItemsSource and copying items out of it.
Here are the changes I am suggesting to correct these issues:
Change OnItemsSourceChanged to:
public void OnItemSourceChanged(IList oldValue, IList newValue)
{
Items.Clear();
if (newValue != null)
{
foreach (var item in newValue)
Items.Add(item);
}
}
Change CreateItemsSource to:
private IList CreateItemsSource()
{
IList list = null;
if (ItemsSourceType != null)
{
ConstructorInfo constructor = ItemsSourceType.GetConstructor(new[] { typeof(int) });
if (constructor == null)
{
constructor = ItemsSourceType.GetConstructor(Type.EmptyTypes);
if (constructor == null)
{
throw new Exception("No usable constructor to build collection");
}
Change PersistChanges to:
public void PersistChanges()
{
IList list = CreateItemsSource();
if (list == null)
return;
//the easiest way to persist changes to the source is to just clear the source list and then add all items to it.
list.Clear();
if (list.IsFixedSize)
{
for (int i = 0; i < Items.Count; ++i)
list[i] = Items[i];
}
else
{
foreach (var item in Items)
{
list.Add(item);
}
}
ItemsSource = list;
}
and delete ComputeItemsSource.