0

I know similar question was asked and as a solution it was suggested to wrap the content in a DataTemplate with Grid and use Grid_Loaded approach. But if I have let's say 10s of DataTemplates that my template selector will select one at a time based on a condition then I need to add this Grid_Loaded event handler for each and every DataTemplate in the xaml. What I'm looking for another approach that wouldn't need me to do duplication of code.

<UserControl x:Class="WHATEVER">
    <UserControl.Resources>
        <ResourceDictionary>
            <my:DetailViewDataTemplateSelector x:Key="myDataTemplateSelector"/>

            <DataTemplate x:Key="Template1">
                <!-- some content -->
            </DataTemplate>

            <DataTemplate x:Key="Template2">
                <!-- some content -->
            </DataTemplate>

            <DataTemplate x:Key="BlankDataTemplate" />

        </ResourceDictionary>
    </UserControl.Resources>

    <ContentPresenter ContentTemplateSelector="{StaticResource myDataTemplateSelector}" Content="{Binding MyViewModelProperty}" />
</UserControl>

And my template selector is defined like (the passed in item is basically the value of MyViewModelProperty of the DataContext)

public class DetailViewDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate selectedTemplate = null;

        if (container is FrameworkElement element)
        {
            selectedTemplate = element.FindResource("BlankDataTemplate") as DataTemplate;

            if (item != null && item is SOME_TYPE selectedNode)
            {
                if (element != null && selectedNode != null)
                {
                    if (SOME_TYPE == SOME_VALUE)
                    {
                        selectedTemplate = element.FindResource("Template1") as DataTemplate;
                    }
                    else
                    {
                        selectedTemplate = element.FindResource("Template2") as DataTemplate;
                    }
                }
            }
        }
        
        return selectedTemplate;
    }
}

Just to let you know I tried using ContentControl instead of ContentPresenter and even created my own CustomContentControl inherited from ContentControl and overriding the OnContentTemplateChanged and OnTemplateChanged handlers, but none of those handlers are called when every time I change the value of MyViewModelProperty.

Note, that the template selector is called and the correct template is returned out based on the MyViewModelProperty value, but the abovementioned OnContentTemplateChanged and OnTemplateChanged handlers are not called after the template is selected. If I have a Grid as the first element in my DataTemplates and subscribe to Loaded event then that is called right after the DataTemplate, therefore, the Grid element is loaded.

Any ideas on how to avoid tying the Loaded handling to the internal grid and rather to fire somehow when we know that the ContentControl's template is selected by the selector and is loaded? Thanks a lot in advance.

Tiger Galo
  • 289
  • 4
  • 15
  • How about the OnApplyTemplate method of a derived ContentPresenter/Control? What exactly are you going to when the template is "loaded"? – Clemens Oct 23 '21 at 07:40
  • I tried overriding the OnApplyTemplate in my inherited custom ContentControl, and the same outcome as it was for OnTemplateChanged or OnContentTemplateChanged, it's not called for some reason. It is called only one time at the very beginning, then with the view model property change bound to the ContentControl's Content property, the DataTemplate is changed thorough the selector, however, the overridden method is not called. That's weird. – Tiger Galo Oct 24 '21 at 01:11
  • And to @Clemens question what exactly I want to do: I try to do after the template is loaded, some of the templates that get loaded have SciCharts that I set data and do some preparation work with the renderable series, and I need to do that work after the template is set and I cannot do that work before the template is set, applied and loaded. – Tiger Galo Oct 24 '21 at 01:15
  • You are doing something utterly wrong, that's for sure. We can't help as you didn't show what you are doing. You only showed a DataTemplateSelector a a DataTemplate - don't know how this can help to understand what you are doing anf how you are doing it. You don't seem to care that your question is about to get closed due to the lack of information. Since we don't know how you are doing things, we can't fix them. All I can say is that what you claim that OnApplyTemplate is never called is not possible, except your control is never loadeed/used (how can we know)? – BionicCode Oct 24 '21 at 09:45
  • OnTemplateChanged is called when the Template property has changed and not when it is applied - Template means ControlTemplate of the ContentControl. OnContentTemplateChanged is called when the Content#Template property has changed but not when it is applied (different scenario). OnApplyTemplate is always! called when the ContentTemplate value is applied to the Content. – BionicCode Oct 24 '21 at 09:45
  • Furthermore, your idea to wait until the moment when the DataTemple is loaded is not clever - it is already loaded, but you want to prepare the data before it is applied. How can the data depend on the UI elements in your template? You must create your data models properly and bind the elements of the DataTemplate to it. Then WPF will do everything for you. Now it's your turn. – BionicCode Oct 24 '21 at 09:45
  • @BionicCode I will start a small sample application to see if all you mentioned works there, perhaps, it's really the current app that has something awkward. Will provide the details after. However, I tried to explain what I'm trying to gain, I change the data template based on a selection of some chart type, then after that template is applied, I need to create the corresponding data and provide it to the SciChart in the data template (some templates have 2 or more charts). That's all I need, after the template is selected and applied then I can provide some data to embedded charts and render – Tiger Galo Oct 25 '21 at 03:31
  • 1
    That'S not how it is done. You must create the required data models, where each data model already contains the required data or knows how to generate/fetch it. You the add this data models to the view (e.g., according to the user's preferences) and then the DataTemplate will be applied, where all elements can bind to the data that is provided by associated model. If you create implicit DataTemplates (you should create a dedicated type for each scenario, then you can even drop the DataTemplateSelector as WPF will automatically select the correct DataTemplate based on the model's type. – BionicCode Oct 25 '21 at 11:20
  • Thanks to @BionicCode advice I started digging into the existing code and found the actual root cause. I refactored the code and everything works well. – Tiger Galo Oct 29 '21 at 20:39

0 Answers0