Notifying of a property change when the binding is not direct #16253
-
Hello, I have a few bindings in my app that are not direct, but instead bind to a property of a property and I just can't get the UI to update even though I am raising the property changed event on all properties. Here is my exact code: MainWindowViewModel:Contains a Tab Manager which contains all the tabs and can switch between them [ObservableProperty] private TabManagerViewModel _tabManager;
public MainWindowViewModel()
{
//Vm1 - Vm4 are just examples for different viewmodels for each tab view
TabManager = new TabManagerViewModel(TabViewModel.ToTab(new Vm1()), TabViewModel.ToTab(new Vm2()),
TabViewModel.ToTab(new Vm3()), TabViewModel.ToTab(new Vm4()));
TabManager.Changed += TabManager_Changed;
}
private void TabManager_Changed()
{
OnPropertyChanged(nameof(TabManager));
} TabManagerViewModel:Contains a list of tabs that can be switched between public event Action? Changed;
public TabManagerViewModel(params TabViewModel[] tabs)
{
Tabs = new ObservableCollection<TabViewModel>(tabs);
SelectTab(0.ToString());
}
[ObservableProperty] private ObservableCollection<TabViewModel> _tabs = new();
[ObservableProperty] private TabViewModel _selectedTab;
[RelayCommand]
private void SelectTab(string index)
{
var newIndex = int.Parse(index);
var newSelectedTab = Tabs[newIndex];
if (SelectedTab != newSelectedTab)
{
newSelectedTab.IsSelected = true;
if(SelectedTab != null)
SelectedTab.IsSelected = false;
SelectedTab = newSelectedTab;
}
else
{
SelectedTab.IsSelected = true;
}
//As you can see I am trying everything here to get the UI to update
OnPropertyChanged(nameof(Tabs));
Tabs.Add(new TabViewModel());
Tabs.RemoveAt(Tabs.Count - 1);
foreach (var tab in Tabs)
{
tab.NotifyOfChanges();
}
Changed?.Invoke();
} TabViewModel: [ObservableProperty] private bool _isSelected;
//The View model of the window to be displayed when this tab is selected
public ViewModelBase ViewModel { get; set; }
public static TabViewModel ToTab(ViewModelBase viewModel)
{
return new TabViewModel
{
ViewModel = viewModel
};
}
public void NotifyOfChanges()
{
OnPropertyChanged(nameof(ViewModel));
OnPropertyChanged(nameof(IsSelected));
} UI in the MainView:The DataContext here is MainViewModel so I have to go through the TabManager to bind to anything tab related <ToggleButton <!-- OtherProperties -->
IsChecked="{Binding TabManager.Tabs[0].IsSelected}"
Command="{Binding TabManager.SelectTabCommand}"
CommandParameter="0"/>
<ToggleButton <!-- OtherProperties -->
IsChecked="{Binding TabManager.Tabs[0].IsSelected}"
Command="{Binding TabManager.SelectTabCommand}"
CommandParameter="1"/>
<ToggleButton <!-- OtherProperties -->
IsChecked="{Binding TabManager.Tabs[0].IsSelected}"
Command="{Binding TabManager.SelectTabCommand}"
CommandParameter="2"/> The display of the tab window: <ContentPresenter Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{Binding TabManager.SelectedTab.ViewModel}"/> I am using the So as you can see, I am binding to properties of properties, etc. and the UI won't update even though I call OnPropertyChanged on all of those. Is there a way to fix this, or should bindings like these be avoided. Also, I do know that there is a built-in TabControl but since I've gone this far, switching over to TabControl is probably going to take more effort than finishing this, I thought. Sorry for throwing so much code on here, and thanks in advance. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Some advice:
|
Beta Was this translation helpful? Give feedback.
Some advice:
ContentPresenter
) are only valid withinControlTemplate
s. UseContentControl
instead.TabControl
orTabStrip
instead of hacking one up like this. You can remove the janky string indexes, too.TabManager
s. It's a common beginner mistake to create multiple VMs by accident and update an instance that isn't binded. You can do this by putting a breakpoint in the TagManager's ctor and check if you get multiple calls.