Reputation: 79
I have a window which contains a TabControl and I would like to have TabItems generated based on user actions. Inside the TabItems I would like to display a UserControl which uses a ViewModel.
I can get everything to display properly, however when the UserControl's ViewModel is updated, the changes are not reflected in the TabItem.
Consider the following simplified example:
MainWindowViewModel.cs
public class MainWindowViewModel : ViewModel
{
public MainWindowViewModel()
{
MyControls = new ObservableCollection<MyControlViewModel>();
}
private ObservableCollection<MyControlViewModel> _myControls;
public ObservableCollection<MyControlViewModel> MyControls
{
get { return _myControls; }
set
{
_myControls = value;
RaisePropertyChangedEvent(nameof(MyControls));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private static MainWindowViewModel _vm;
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
_vm = DataContext as MainWindowViewModel;
var myItem1 = new MyItem("Item1");
var myItem2 = new MyItem("Item2");
var myControlVm = new MyControlViewModel(new ObservableCollection<MyItem> { myItem1, myItem2 });
_vm.MyControls.Add(myControlVm);
}
}
MainWindow.xaml
<Window x:Class="TabControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TabControlTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<TabControl ItemsSource="{Binding MyControls}">
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type local:MyControlViewModel}">
<local:MyControl />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
MyControlViewModel.cs
public class MyControlViewModel : ViewModel
{
public MyControlViewModel(ObservableCollection<MyItem> items)
{
MyItems = items;
}
private ObservableCollection<MyItem> _myItems;
public ObservableCollection<MyItem> MyItems
{
get { return _myItems; }
set
{
_myItems = value;
RaisePropertyChangedEvent(nameof(MyItems));
}
}
}
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var vm = DataContext as MyControlViewModel;
foreach (var item in vm.MyItems)
{
item.ShouldBold = !item.ShouldBold;
}
}
}
MyControl.xaml
<UserControl x:Class="TabControlTest.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TabControlTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ListBox ItemsSource="{Binding MyItems}" MouseDoubleClick="ListBox_MouseDoubleClick">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Content" Value="{Binding Label}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<DataTrigger Binding="{Binding ShouldBold}" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
</Grid>
</UserControl>
MyItem.cs
public class MyItem : ViewModel
{
public MyItem(string label)
{
Label = label;
}
private string _label;
public string Label
{
get { return _label; }
set
{
_label = value;
RaisePropertyChangedEvent(nameof(Label));
}
}
private bool _shouldBold;
public bool ShouldBold
{
get { return _shouldBold; }
set
{
_shouldBold = value;
RaisePropertyChangedEvent(nameof(ShouldBold));
}
}
}
When I double-click on the MyControl
in the MainWindow I would expect the items to be displayed in bold via the ListBox_MouseDoubleClick
method, however the style is not applying. When I step through the ListBox_MouseDoubleClick
method, I can see that the ShouldBold
is being updated correctly, but again the style is not applying.
Is there another way I should structure this or something else I need to do to have the style apply? Any help is appreciated!
Edit
Here's my ViewModel.cs
public class ViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 0
Views: 492
Reputation: 169200
Your ViewModel
class should implement INotifyPropertyChanged
:
public class ViewModel : INotifyPropertyChanged
...
Upvotes: 3