Julius
Julius

Reputation: 745

WPF: When changing a ContentControl's Content, the new content object is NOT firing the loaded event

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

Answers (1)

Y. H&#246;gger
Y. H&#246;gger

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

Related Questions