Open gerfen opened 2 years ago
Hi @gerfen,
If I remember correctly OnViewLoaded
is called the first time a view is loaded, OnViewAttached
should be called right after and OnViewReady
should be called when the view is has had its layout updated. This is triggered from ViewModelBinder.Bind
. Can you make a repro of the issues so that we could debug it?
/KasperSK
Hi @KasperSK,
I'm working on a repro. I hope to have something in a day or two.
@gerfen where you able to create a repo?
@vb2ae Unfortunately I have not been able to create a repro yet. At the moment, I am contemplating going a different direction. I will close this issue for now and will reopen if appropriate.
@KasperSK and @vb2ae - I was finally able to create a repro of this issue. There seems to be an issue integrating Avalon Dock with Caliburn.Micro. The repro of the issue can be found here: https://github.com/gerfen/CaliburnMicroAvalonDockBug. As a reminder, the OnViewAttached
, OnViewReady
and OnViewLoaded
methods of the conducted view models are not called. I found a work around which allows the OnViewAttached
and OnViewReady
methods to be called but I have not been able to get OnViewLoaded
to be called.
The work around looks like this:
private async Task ActivateItemAsync<TViewModel>(CancellationToken cancellationToken = default)
where TViewModel : Screen
{
// NOTE: This is the hack to get OnViewAttached and OnViewReady methods to be called on conducted ViewModels. Also note
// OnViewLoaded is not called.
var viewModel = IoC.Get<TViewModel>();
viewModel.Parent = this;
viewModel.ConductWith(this);
var view = ViewLocator.LocateForModel(viewModel, null, null);
ViewModelBinder.Bind(viewModel, view, null);
await ActivateItemAsync(viewModel, cancellationToken);
}
I call this method like so in my Conductor
await ActivateItemAsync<Tab1ViewModel>();
await ActivateItemAsync<Tab2ViewModel>();
await ActivateItemAsync<DesignSurfaceViewModel>();
The code also demonstrates another issue which I believe is related to OnViewLoaded
never being called on the conducted view models. The view appears to be completely severed from the view model, almost like there are two instances of the view - one which is connected to the view model which is not shown in the visual tree and another which is disconnected from the view model but is displayed in the visual tree. I don't know this for sure but when I try to draw a shape on a Canvas
control, nothing happens, even if I call a method on the View.
The UI looks like this:
The blue From View
shape is drawn from the XAML for the view. The orange shape with the words From View
just below it is drawn from the OnInitialized
method of the view. When I click the Draw Shape
button, another blue shape with the words From ViewModel
should appear yet nothing happens.
The logs below show the various life cycle methods being called.
2022-08-01 11:16:57.111 -07:00 [Information] [CaliburnMicroAvalonDockBug.Bootstrapper] Application is starting.
2022-08-01 11:16:57.574 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] Drawing `From View` shape from the view's OnInitialized method.
2022-08-01 11:16:57.578 -07:00 [Information] [CaliburnMicroAvalonDockBug.ViewModels.DesignSurfaceViewModel] DesignSurfaceViewModel.OnViewAttached Called.
2022-08-01 11:16:58.662 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] Drawing `From View` shape from the view's OnInitialized method.
2022-08-01 11:16:58.670 -07:00 [Information] [CaliburnMicroAvalonDockBug.ViewModels.DesignSurfaceViewModel] DesignSurfaceViewModel.OnViewReady Called.
2022-08-01 11:17:01.102 -07:00 [Information] [CaliburnMicroAvalonDockBug.ViewModels.DesignSurfaceViewModel] DesignSurfaceViewModel.DrawShape called.
2022-08-01 11:17:01.106 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] DesignSurfaceView.AddControl called - adding Border to DesignSurfaceCanvas.
2022-08-01 11:17:02.813 -07:00 [Information] [CaliburnMicroAvalonDockBug.Bootstrapper] Application is exiting.
2022-08-01 11:18:01.813 -07:00 [Information] [CaliburnMicroAvalonDockBug.Bootstrapper] Application is starting.
2022-08-01 11:18:02.264 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] Drawing `From View` shape from the view's OnInitialized method.
2022-08-01 11:18:02.268 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] DesignSurfaceView.AddControl called - adding Border to DesignSurfaceCanvas.
2022-08-01 11:18:02.271 -07:00 [Information] [CaliburnMicroAvalonDockBug.ViewModels.DesignSurfaceViewModel] DesignSurfaceViewModel.OnViewAttached Called.
2022-08-01 11:18:03.290 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] Drawing `From View` shape from the view's OnInitialized method.
2022-08-01 11:18:03.294 -07:00 [Information] [CaliburnMicroAvalonDockBug.Views.DesignSurfaceView] DesignSurfaceView.AddControl called - adding Border to DesignSurfaceCanvas.
2022-08-01 11:18:03.303 -07:00 [Information] [CaliburnMicroAvalonDockBug.ViewModels.DesignSurfaceViewModel] DesignSurfaceViewModel.OnViewReady Called.
Note that the log message Drawing 'From View' shape from the view's OnInitialized method.
appears twice yet only one orange shape appears in the visual tree:
I realize this may also be an issue with Avalon Dock but that fact that the OnViewLoaded
method never gets called seems to point to Caliburn.Micro. Please let me know if I can provide any further detail.
Thanks!
Another data point... If I use an updated version of Gemini (using the latest versions of CM and Avalon Dock) I can add shapes to a canvas without any issue. One of the main differences is that Gemini uses MEF. I'm not sure if that's the difference or if the there's some other internal plumbing which addresses the issue. What I can say is that all three of theOnView*
methods are called in this order ->OnViewAttached
, OnViewReady
, followed by OnViewLoaded
.
My updated Gemini code can be found here: https://github.com/gerfen/gemini/tree/di-spike
Hi @gerfen,
Thanks for the repo! I will have a look at this later today.
/Kasper
I have a little more info. If I use binding via XAML (i.e. binding to ItemsSource on a ListView) then I can draw on the canvas
I am working on a WPF app and I have a view model which inherits from Conductor.Collection.AllActive. I add child views to the Items collection like so:
Both ViewModel1 and ViewModel2 inherit from Screen so I would expect the
OnViewAttached
,OnViewLoaded
andOnViewReady
methods to be fired but they do not.OnActivateAsync
as well asOnInitalizeAsync
are called as expected.As an experiment, I wrote the following method on my Conductor implementation:
And I active my child views like so:
This results in
OnViewAttached
andOnViewReady
methods getting called on the child views but notOnViewLoaded
. I understand that under normal circumstancesOnViewLoaded
should only be called the first time the view is loaded but I would expectOnViewLoaded
to be called at least once but it is not.What am I missing? Is there a better way to achieve my objective?