Reputation: 745
Problem:
I am unable to hook into the point in time after I change a ContentControl's content, the DataTemplate from a DataTemplateSelector has been applied, and all visual layout has been completed, i.e. the new content is Loaded.
Setup:
A custom control called 'KeyboardHost' which extends a ContentControl.
ContentControl.Content is bound (using a multi-binding) to 2 notification properties, via a value converter which combines the 2 bound properties into an object of type 'KeyboardCriteria'.
'KeyboardCriteria' is a public class, but I have also tried making this a FrameworkElement, Control and UserControl so that I could try to hook into the Initialized, Loaded etc events.
ContentControl.ContentTemplateSelector is a custom selector class (below) which returns a DataTemplate based on the ContentControl.Content (the 'KeyboardCriteria').
The ContentControl.ContentTemplateSelector's DataTemplates are properties on the selector and are initialised and assigned in the resources section of my MainView.
Attempts:
I have attached/overridden the following ContentControl events:
Initialized
Loaded
OnContentChanged
OnContentTemplateChanged
I have attached/override the following 'KeyboardCriteria' (defined as a FrameworkElement) events:
Initialized
Loaded
OnApplyTemplate
OnTemplateChanged
TemplateDP callback
Observations:
On startup:
KeyboardHost: OnTemplateChanged
KeyboardHost: ContentChanged
KeyboardCriteria: Initialized
KeyboardCriteria: Loaded
When changing one of the bound criteria properties (thus creating a new KeyboardCriteria object):
KeyboardHost: ContentChanged
KeyboardCriteria: Initialized
N.B. The lack of a Loaded event on the ContentControl.Content object (the 'KeyboardCriteria').
Next steps:
I think I will scrap the idea of using a DataTemplateSelector entirely and build the selection logic into my ContentControl, as this is already a CustomControl. I am hoping by manually creating the Content (and populating it) I can avoid the use of the DataTemplates that I currently use in the selection logic, as I suspect this is part of the problem.
...
CODE SAMPLES:
MainViewModel:
Exposes 'Keyboard' property, which initially has a non-null value.
MainView:
<controls:KeyboardHost Grid.Row="0"
ContentTemplateSelector="{StaticResource KeyboardDataTemplateSelector}">
<ContentControl.Content>
<MultiBinding Converter="{StaticResource KeyboardCriteriaValueConverter}" Mode="OneWay">
<Binding Source="{x:Static properties:Settings.Default}" Path="Language" />
<Binding Path="Keyboard" />
</MultiBinding>
</ContentControl.Content>
</controls:KeyboardHost>
KeyboardCriteriaValueConverter:
Convert method only, ConvertBack throws NotImplementedException.
Logic has been simplified to remove extra logic to check value types, count, etc.
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return new KeyboardCriteria
{
Language = values[0],
Keyboard = values[1]
};
}
KeyboardDataTemplateSelector:
public class KeyboardDataTemplateSelector : DataTemplateSelector
{
//TEMPLATE PROPERTIES HERE - THESE ARE SET IN THE RESOURCE DEFINITION
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var criteria = item as KeyboardCriteria;
//LOGIC TO RETURN THE APPROPRIATE KEYBOARD DATA TEMPLATE BASED ON THE criteria
}
}
Thanks for any insight you can provide.
Upvotes: 3
Views: 4027
Reputation: 21
I know this is an old thread, but I recently stumbled over the same problem. Here is what I did, to solve it, in case someone else can use it.
After I set the Content of ContentControl i do the following:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, (Action)OnAfterRendered);
Then in the "OnAfterRendered" method i can work with the ContentControl with applied DataTemplates
Upvotes: 2