I've got a collection of ViewModels that are rendered as tabs using a style to pull out the relevant content to display on the tab:
public class TabViewModel : DependencyObject
{
public object Content
{
get { return (object)GetValue(ContentProperty); }
set
{
SetValue(ContentProperty, value);
}
}
}
Here's the TabControl:
<TabControl
ItemsSource={Binding MyCollectionOfTabViewModels}"
ItemContainerStyle="{StaticResource TabItemStyle}" />
And here's the style
<Style TargetType="TabItem" x:Key="TabItemStyle">
<Setter Property="Content" Value="{Binding Content}"/>
</Style>
We are creating an instance of a usercontrol and setting the "Content" property of the TabViewModel to that so that the usercontrol gets displayed in the TabItem's Content area.
MyCollectionOfViewModels.Add(new TabViewModel()
{
Content = new MyUserControl();
});
My question is, I would like to allow a MyUserControl (or any of its sub controls) added to the TabViewModel's Content property to be allowed to raise an event that the TabViewModel handles.
Anyone know how I would do that?
We've experimented using RoutedEvents and RoutedCommands, but haven't been able to get anything to work 100% and have it be compatible with MVVM. I really think that this could be done with a RoutedEvent or RoutedCommand, but I don't seem to be able to get this to work.
Note: I've removed some of the relevant Prism-specific code, but if you are wondering why we do something so silly, it is because we are trying to stay control agnostic by using Prism's RegionManager.
You could add a State property to your TabViewModel, and check the DependencyPropertyChanged events.
So imagine the following enum:
public enum TabViewModelState
{
True,
False,
FileNotFound
}
Then add a State property to your TabViewModel of this enum:
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register("State", typeof(TabViewModelState), typeof(TabViewModel), new PropertyMetadata(OnStateChanged));
private static void OnStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
TabViewModel viewModel= (TabViewModel)obj;
//Do stuff with your viewModel
}
Use a two-way binding to this property in your control:
<CheckBox Checked="{Binding Path=State, Converter={StaticResource StateToBooleanConverter}, Mode=TwoWay}" />
And last but not least implement the converter that will convert to and from the original value needed for the control.. (in my example boolean <--> TabViewModelState):
public class StateToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TabViewModelState state = (TabViewModelState) value;
return state == TabViewModelState.True;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool result = (bool) value;
return result ? TabViewModelState.True : TabViewModelState.False;
}
}
So now you have a State property that is managed by the UI, and throws changed events when you need to respond..
Hope this helps!