Conductor<T>'s ActiveItem not Updating View
See original GitHub issueProblem
I am using Caliburn Micro in WPF on Windows / desktop.
I have the following very simple ShellView.xaml
:
<ContentControl Caliburn:View.Model="{Binding ActiveItem}"/>
I am using a Conductor<IViewModelBase>
to display the ActiveItem
.
My ShellViewModel.cs
(Conductor
) looks like this:
internal sealed class ShellViewModel : Conductor<IViewModelBase>, IShellViewModel
{
private readonly IMainViewModel mainViewModel;
public ShellViewModel(IWelcomeViewModel welcomeViewModel, IMainViewModel mainViewModel)
{
this.mainViewModel = mainViewModel;
welcomeViewModel.Deactivated += WelcomeViewModel_Deactivated;
ChangeActiveItem(welcomeViewModel, false); // <-- Initial ActiveItem
}
private void WelcomeViewModel_Deactivated(object sender, DeactivationEventArgs e)
{
((IWelcomeViewModel)sender).Deactivated -= WelcomeViewModel_Deactivated;
ChangeActiveItem(mainViewModel, true); // <-- Changes ActiveItem to MainViewModel
}
}
For the purposes of testing, WelcomeViewModel
TryClose()
-s after 10 seconds:
internal class WelcomeViewModel : ViewModelBase, IWelcomeViewModel
{
public WelcomeViewModel()
{
Timer timer = new Timer(10_000) { Enabled = true };
timer.Elapsed += (sender, e) => TryClose();
timer.Start();
}
}
The expected result is that the view should update its UserControl
to match whichever ViewModel
has been bound to, which is the ActiveItem
, which changes after 10 seconds. However, it doesn’t - the screen becomes blank (white).
Attempted Solutions
I’ve tried swapping the two ViewModels around - having the MainViewModel
go first - and in that case, the MainViewModel
is displayed, however the screen does not end up displaying WelcomeViewModel
; it goes blank instead.
Subsequently, I tried manually notifying of change.
NotifyOfPropertyChange(() => ActiveItem);
This also did not work.
I have also tried using convention binding on the ShellView.xaml
(x:Name="ActiveItem"
) which also did not work.
Finally, I remember once having to activate my conductor (Conductor<T>.Collection.OneActive
) in order for it to properly activate/deactivate views, so I tried that as well (in ShellViewModel.cs
):
ScreenExtensions.TryActivate(this);
also to no avail.
What worked, however, was having a custom IViewModelBase
property (e.g. ActiveView
), and binding to that instead, changing it whenever ChangeActiveItem
is called.
Question
I can, of course, fix this issue by either rolling my own ActiveItem
, or not using Conductor<T>
at all, however I would like to do this properly.
Is there some kind of trick to using Conductor<T>
, or is this just a bug? I have searched plenty on the internet and nothing seemed to work.
Issue Analytics
- State:
- Created 6 years ago
- Comments:11 (4 by maintainers)
Top GitHub Comments
Okay, thanks for all the help. You can close the issue if you wish.
From what I can tell there’s a bit of a race condition happening here. Calling
TryClose
onWelcomeViewModel
will deactivate that view model, and remove it from being theActiveItem
. However by listening for that event and jumping in the middle we’re trying to replace theActiveItem
before the previously one is finished being closed.