In my experimental Project, I created a View with some nested SubControls (of type Catel.Windows.Controls.UserControl) - kinda like Catel.Examples.WPF.AdvancedDemo does in the HouseView (although that example does NOT have the same problem.)
Parts of the "main view" XAML:
<ItemsControl ItemsSource="{Binding Orders}" Grid.ColumnSpan="2" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<views:OrderControl DataContext="{Binding}"/>
<Line Height="2" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So I basically have a ItemsControl, which has an ItemTemplate that creates a OderControl View.
The Problem is, that for each OrderControl item, the ViewModel is instantiated twice (and for the first SaveAsync is called).
I extracted the stack-trace for both instantiations and the call to SaveAsync - hope someone can give me some insights as for why I experience those problems:
First Constructor Call ViewModel:
CatelTest.WPF.Shared.dll!CatelTest.WPF.Shared.ViewModels.OrderViewModel.OrderViewModel(CatelTest.Data.Shared.Orders order) Line 18 C# [External Code] Catel.Core.dll!Catel.IoC.TypeFactory.TryCreateToConstruct(System.Type typeToConstruct, System.Reflection.ConstructorInfo constructor, object[] parameters, bool checkConstructor, bool hasMoreConstructorsLeft) Line 546 C# Catel.Core.dll!Catel.IoC.TypeFactory.CreateInstanceWithSpecifiedParameters(System.Type typeToConstruct, object[] parameters, bool autoCompleteDependencies, bool preventCircularDependencies) Line 295 C# Catel.Core.dll!Catel.IoC.TypeFactory.CreateInstanceWithParametersAndAutoCompletion(System.Type typeToConstruct, object[] parameters) Line 155 C# Catel.MVVM.dll!Catel.MVVM.ViewModelFactory.CreateViewModel(System.Type viewModelType, object dataContext) Line 89 C# Catel.MVVM.dll!Catel.MVVM.Providers.LogicBase.ConstructViewModelUsingArgumentOrDefaultConstructor(object injectionObject, System.Type viewModelType) Line 1079 C# Catel.MVVM.dll!Catel.MVVM.Providers.LogicBase.ConstructViewModelUsingArgumentOrDefaultConstructor(object injectionObject) Line 1005 C# Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.UpdateDataContextToUseViewModelAsync(object newDataContext) Line 691 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.OnTargetViewLoaded() Line 412 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Providers.LogicBase.OnTargetViewLoadedInternal(object sender, System.EventArgs e) Line 681 C# Catel.MVVM.dll!Catel.MVVM.Providers.LogicBase.OnViewLoadedManagerLoaded(object sender, Catel.MVVM.Views.ViewLoadEventArgs e) Line 610 C# Catel.Core.dll!Catel.WeakEventListener.OnEvent(object source, Catel.MVVM.Views.ViewLoadEventArgs eventArgs) Line 745 C# Catel.MVVM.dll!Catel.MVVM.Views.ViewLoadManager.InvokeViewLoadEvent(Catel.MVVM.Views.IView view, Catel.MVVM.Views.ViewLoadStateEvent viewLoadStateEvent) Line 349 C# Catel.MVVM.dll!Catel.MVVM.Views.ViewLoadManager.RaiseLoaded(Catel.MVVM.Views.IView view) Line 293 C# Catel.MVVM.dll!Catel.MVVM.Views.ViewLoadManager.OnViewInfoLoaded(object sender, System.EventArgs e) Line 241 C# Catel.MVVM.dll!Catel.MVVM.Views.WeakViewInfo.OnLoaded() Line 207 C# Catel.MVVM.dll!Catel.MVVM.Views.WeakViewInfo.OnViewLoadStateLoaded(object sender, System.EventArgs e) Line 181 C# Catel.Core.dll!Catel.WeakEventListener.OnEvent(object source, System.EventArgs eventArgs) Line 745 C# [External Code] Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindow.AnonymousMethod__0() Line 499 C# Catel.MVVM.dll!Catel.Windows.Threading.DispatcherExtensions.Invoke(System.Windows.Threading.Dispatcher dispatcher, System.Action action, bool onlyBeginInvokeWhenNoAccess) Line 139 C# Catel.MVVM.dll!Catel.Windows.Threading.DispatcherExtensions.InvokeIfRequired(System.Windows.Threading.Dispatcher dispatcher, System.Action action) Line 95 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindow(System.Windows.FrameworkElement window, bool showModal) Line 507 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindowAsync(System.Windows.FrameworkElement window, bool showModal) Line 537 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowDialogAsync(string name, object data, System.EventHandler completedProc) Line 338 C# [External Code] Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowDialogAsync(Catel.MVVM.IViewModel viewModel, System.EventHandler completedProc) Line 291 C# [External Code] CatelTest.WPF.Shared.dll!CatelTest.WPF.Shared.ViewModels.MainWindowViewModel.OnEditCustomerCommandExecute() Line 115 C# Catel.MVVM.dll!Catel.MVVM.TaskCommand..ctor.AnonymousMethod__0(object executeParameter, System.Threading.CancellationToken cancellationToken, System.IProgress progress) Line 52 C# Catel.MVVM.dll!Catel.MVVM.TaskCommand.Execute(bool ignoreCanExecuteCheck, object parameter) Line 234 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Command.Execute(object parameter) Line 242 C# Catel.MVVM.dll!Catel.MVVM.Command.Execute(object parameter) Line 233 C# Catel.MVVM.dll!Catel.Windows.Interactivity.CommandTriggerActionBase.ExecuteCommand(object parameter) Line 299 C# Catel.MVVM.dll!Catel.Windows.Interactivity.EventToCommand.Invoke(object parameter) Line 138 C#
First Save Call ViewModel:
CatelTest.WPF.Shared.dll!CatelTest.WPF.Shared.ViewModels.OrderViewModel.SaveAsync() Line 219 C# Catel.MVVM.dll!Catel.MVVM.ViewModelBase.SaveViewModelAsync() Line 1753 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.CloseAndDisposeViewModelAsync(bool? result) Line 748 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.UpdateDataContextToUseViewModelAsync(object newDataContext) Line 688 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.OnTargetViewDataContextChanged(Catel.MVVM.Views.DataContextChangedEventArgs e, object sender) Line 506 C# [External Code] Catel.Core.dll!Catel.EventHandlerExtensions.SplitInvoke(System.Delegate handler, object[] args) Line 233 C# Catel.Core.dll!Catel.EventHandlerExtensions.SafeInvoke(System.EventHandler handler, object sender, Catel.MVVM.Views.DataContextChangedEventArgs e) Line 143 C# Catel.MVVM.dll!Catel.Windows.Controls.UserControl..ctor.AnonymousMethod__11_5(object sender, Catel.Windows.Data.DependencyPropertyValueChangedEventArgs e) Line 126 C# Catel.MVVM.dll!Catel.Windows.Data.DependencyPropertyChangedHelper.OnDependencyPropertyChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) Line 271 C# [External Code] Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindow.AnonymousMethod__0() Line 499 C# Catel.MVVM.dll!Catel.Windows.Threading.DispatcherExtensions.Invoke(System.Windows.Threading.Dispatcher dispatcher, System.Action action, bool onlyBeginInvokeWhenNoAccess) Line 139 C# Catel.MVVM.dll!Catel.Windows.Threading.DispatcherExtensions.InvokeIfRequired(System.Windows.Threading.Dispatcher dispatcher, System.Action action) Line 95 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindow(System.Windows.FrameworkElement window, bool showModal) Line 507 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindowAsync(System.Windows.FrameworkElement window, bool showModal) Line 537 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowDialogAsync(string name, object data, System.EventHandler completedProc) Line 338 C# [External Code] Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowDialogAsync(Catel.MVVM.IViewModel viewModel, System.EventHandler completedProc) Line 291 C# [External Code] CatelTest.WPF.Shared.dll!CatelTest.WPF.Shared.ViewModels.MainWindowViewModel.OnEditCustomerCommandExecute() Line 115 C# Catel.MVVM.dll!Catel.MVVM.TaskCommand..ctor.AnonymousMethod__0(object executeParameter, System.Threading.CancellationToken cancellationToken, System.IProgress progress) Line 52 C# Catel.MVVM.dll!Catel.MVVM.TaskCommand.Execute(bool ignoreCanExecuteCheck, object parameter) Line 234 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Command.Execute(object parameter) Line 242 C# Catel.MVVM.dll!Catel.MVVM.Command.Execute(object parameter) Line 233 C# Catel.MVVM.dll!Catel.Windows.Interactivity.CommandTriggerActionBase.ExecuteCommand(object parameter) Line 299 C# Catel.MVVM.dll!Catel.Windows.Interactivity.EventToCommand.Invoke(object parameter) Line 138 C#
Second Constructor Call ViewModel:
CatelTest.WPF.Shared.dll!CatelTest.WPF.Shared.ViewModels.OrderViewModel.OrderViewModel(CatelTest.Data.Shared.Orders order) Line 18 C# [External Code] Catel.Core.dll!Catel.IoC.TypeFactory.TryCreateToConstruct(System.Type typeToConstruct, System.Reflection.ConstructorInfo constructor, object[] parameters, bool checkConstructor, bool hasMoreConstructorsLeft) Line 546 C# Catel.Core.dll!Catel.IoC.TypeFactory.CreateInstanceWithSpecifiedParameters(System.Type typeToConstruct, object[] parameters, bool autoCompleteDependencies, bool preventCircularDependencies) Line 295 C# Catel.Core.dll!Catel.IoC.TypeFactory.CreateInstanceWithParametersAndAutoCompletion(System.Type typeToConstruct, object[] parameters) Line 155 C# Catel.MVVM.dll!Catel.MVVM.ViewModelFactory.CreateViewModel(System.Type viewModelType, object dataContext) Line 89 C# Catel.MVVM.dll!Catel.MVVM.Providers.LogicBase.ConstructViewModelUsingArgumentOrDefaultConstructor(object injectionObject, System.Type viewModelType) Line 1079 C# Catel.MVVM.dll!Catel.MVVM.Providers.LogicBase.ConstructViewModelUsingArgumentOrDefaultConstructor(object injectionObject) Line 1005 C# Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.UpdateDataContextToUseViewModelAsync(object newDataContext) Line 691 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Providers.UserControlLogic.OnTargetViewDataContextChanged(Catel.MVVM.Views.DataContextChangedEventArgs e, object sender) Line 506 C# [External Code] Catel.Core.dll!Catel.EventHandlerExtensions.SplitInvoke(System.Delegate handler, object[] args) Line 233 C# Catel.Core.dll!Catel.EventHandlerExtensions.SafeInvoke(System.EventHandler handler, object sender, Catel.MVVM.Views.DataContextChangedEventArgs e) Line 143 C# Catel.MVVM.dll!Catel.Windows.Controls.UserControl..ctor.AnonymousMethod__11_5(object sender, Catel.Windows.Data.DependencyPropertyValueChangedEventArgs e) Line 126 C# Catel.MVVM.dll!Catel.Windows.Data.DependencyPropertyChangedHelper.OnDependencyPropertyChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e) Line 271 C# [External Code] Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindow.AnonymousMethod__0() Line 499 C# Catel.MVVM.dll!Catel.Windows.Threading.DispatcherExtensions.Invoke(System.Windows.Threading.Dispatcher dispatcher, System.Action action, bool onlyBeginInvokeWhenNoAccess) Line 139 C# Catel.MVVM.dll!Catel.Windows.Threading.DispatcherExtensions.InvokeIfRequired(System.Windows.Threading.Dispatcher dispatcher, System.Action action) Line 95 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindow(System.Windows.FrameworkElement window, bool showModal) Line 507 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowWindowAsync(System.Windows.FrameworkElement window, bool showModal) Line 537 C# Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowDialogAsync(string name, object data, System.EventHandler completedProc) Line 338 C# [External Code] Catel.MVVM.dll!Catel.Services.UIVisualizerService.ShowDialogAsync(Catel.MVVM.IViewModel viewModel, System.EventHandler completedProc) Line 291 C# [External Code] CatelTest.WPF.Shared.dll!CatelTest.WPF.Shared.ViewModels.MainWindowViewModel.OnEditCustomerCommandExecute() Line 115 C# Catel.MVVM.dll!Catel.MVVM.TaskCommand..ctor.AnonymousMethod__0(object executeParameter, System.Threading.CancellationToken cancellationToken, System.IProgress progress) Line 52 C# Catel.MVVM.dll!Catel.MVVM.TaskCommand.Execute(bool ignoreCanExecuteCheck, object parameter) Line 234 C# [External Code] Catel.MVVM.dll!Catel.MVVM.Command.Execute(object parameter) Line 242 C# Catel.MVVM.dll!Catel.MVVM.Command.Execute(object parameter) Line 233 C# Catel.MVVM.dll!Catel.Windows.Interactivity.CommandTriggerActionBase.ExecuteCommand(object parameter) Line 299 C# Catel.MVVM.dll!Catel.Windows.Interactivity.EventToCommand.Invoke(object parameter) Line 138 C#
Update: I checked if the DataContext does change multiple times, which the stacktrace suggests - by attaching to "UserControl.DataContextChanged" Event - but it is called only once.
What is also interesting: I attached to the Event "Unloaded" of the Control, and guess what the DataContext is? One would expect it to be the OrderViewModel, yet it is an "Order" ModelObject?!
Update#2: Attaching to the same Events on "RoomView" (AdvancedDemo) - same behaviour...the DataContext is a "RoomModel" in Unloaded-Event.
Update#3: I print out the Name of the DataContext in the UI now....and guess what - it is the ViewModel. Now I am totally confused hehe. So what does Catel do? Change the DataContext of the first child in the UserControl? (the "LayoutRoot")
Update#4: The Catel UserControl indeed injects the ViewModel DataContext infact not "in itself", but in a Sub-Control (in case of Catel UserControl 4.4 the "first Grid Child".
Update #5: I did as you suggested, here are parts of the debug-output - I highlighted the part where the catel-usercontrol goes crazy:
13:35:18:857 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Initializing view model container to manage ViewToViewModel mappings 13:35:18:860 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Initializing view model 'OrderViewModel' 13:35:18:860 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Initialized view model 'OrderViewModel' 13:35:18:861 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Initialized view model container to manage ViewToViewModel mappings 13:35:18:865 => [DEBUG] [Catel.MVVM.Providers.LogicBase] [10] DataContext of TargetView 'OrderControl' has changed to 'Orders' CatelTest.WPF.DataService.vshost.exe Information: 0 : 13:35:19:553 => [INFO] [Catel.MVVM.ViewModelBase] [10] Saved view model 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' 13:35:19:555 => [DEBUG] [Catel.MVVM.ViewModelManager] [10] Unregistering model 'Orders' with view model 'OrderViewModel' (id = '3') 13:35:19:555 => [DEBUG] [Catel.MVVM.ViewModelManager] [10] Unregistered model 'Orders' with view model 'OrderViewModel' (id = '3') 13:35:19:557 => [DEBUG] [Catel.Data.ModelBase] [10] IEditableObject.EndEdit 13:35:19:559 => [DEBUG] [Catel.MVVM.ViewModelManager] [10] Unregistering all models of view model 'OrderViewModel' (id = '3') 13:35:19:560 => [DEBUG] [Catel.MVVM.ViewModelManager] [10] Unregistered all '0' models of view model 'OrderViewModel' (id = '3') 13:35:19:564 => [DEBUG] [Catel.MVVM.ViewModelCommandManager] [10] Unregistering commands on view model 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' with unique identifier '3' 13:35:19:564 => [DEBUG] [Catel.MVVM.ViewModelCommandManager] [10] Unregistered commands on view model 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' with unique identifier '3' CatelTest.WPF.DataService.vshost.exe Information: 0 : 13:35:19:566 => [INFO] [Catel.MVVM.ViewModelBase] [10] Closed view model 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' 13:35:19:568 => [DEBUG] [Catel.MVVM.ManagedViewModel] [10] Removed view model instance, currently containing '0' instances of type 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' 13:35:19:568 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Initializing view model 'null' 13:35:19:569 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Uninitializing view model 'OrderViewModel' 13:35:19:569 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Uninitialized view model 'OrderViewModel' 13:35:19:570 => [DEBUG] [Catel.MVVM.Views.ViewToViewModelMappingHelper] [10] Initialized view model 'null' 13:35:19:570 => [DEBUG] [Catel.MVVM.Providers.LogicBase] [10] Using IViewModelFactory 'Catel.MVVM.ViewModelFactory' to instantiate the view model 13:35:19:571 => [DEBUG] [Catel.IoC.TypeFactory] [10] Calling constructor.Invoke with the right parameters 13:35:19:571 => [DEBUG] [Catel.MVVM.ViewModelBase] [10] Creating view model of type 'OrderViewModel' with unique identifier 4 13:35:19:572 => [DEBUG] [Catel.MVVM.ViewModelCommandManager] [10] Creating a ViewModelCommandManager for view model 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' with unique identifier '4' 13:35:19:573 => [DEBUG] [Catel.MVVM.ViewModelCommandManager] [10] Created a ViewModelCommandManager for view model 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' with unique identifier '4' 13:35:19:573 => [DEBUG] [Catel.MVVM.ManagedViewModel] [10] Added view model instance, currently containing '1' instances of type 'CatelTest.WPF.Shared.ViewModels.OrderViewModel' 13:35:20:139 => [DEBUG] [Catel.MVVM.ViewModelManager] [10] Registering model 'Orders' with view model 'OrderViewModel' (id = '4') 13:35:20:140 => [DEBUG] [Catel.MVVM.ViewModelManager] [10] Registered model 'Orders' with view model 'OrderViewModel' (id = '4') 13:35:20:140 => [DEBUG] [Catel.Data.ModelBase] [10] IEditableObject.BeginEdit