Search code examples
wpfcustom-controls

OnApplyTemplate never called in Custom Control


I tested some codes about custom control but OnApplyTemplate is never called. I'm sure i have the correct static methods and assemblyInfo.cs setup; A whole version is inclued. https://www.dropbox.com/sh/n4uusow5z6ncd9c/AADMrI9jlr-qss7O2qyAg-5Aa?dl=0

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    Console.WriteLine("Begin");
    //get the part controls 
    PART_MasterGrid = GetTemplateChild("PART_MasterGrid") as Grid;
    PART_RightCntl = GetTemplateChild("PART_RightCntl") as StackPanel;
    PART_LeftCntl = GetTemplateChild("PART_LeftCntl") as StackPanel;
    PART_BottomCntl = GetTemplateChild("PART_BottomCntl") as StackPanel;
    PART_ParentPanel = GetTemplateChild("PART_ParentPanel") as DockPanel;
    //verify master grid exist
    if (PART_MasterGrid == null)
        return;
    //setup parent grid
    var parentGrid = new Grid();
    SetUpParentGrid(parentGrid);
    //set up layers
    var layer0 = Layers.FirstOrDefault(x => x.Level == 0);
    if (layer0 == null)
        return;

    var columnLayers =
        Layers.Select(x => x).Where(x => x.Level > 0 && x.Orientation == Layer.LayerOrientation.Column).OrderBy(
                x => x.Level);
    var rowLayers =
        Layers.Select(x => x).Where(x => x.Level > 0 && x.Orientation == Layer.LayerOrientation.Row).OrderBy(x => x.Level);
    var item = SetupLayer0(layer0,
                               columnLayers,
                               rowLayers.Count());
    parentGrid.Children.Add(item);
    Grid.SetRow(item, 0);
    //setup the column grid layers
    if (columnLayers.Any())
    {
        foreach (var layer in columnLayers)
        {
            SetupColumnLayers(parentGrid, layer, columnLayers.Count());
        }
    }
    //setup the row grid layers
    if (rowLayers.Any())
    {
        foreach (var layer in rowLayers)
        {
            SetupRowLayers(item, layer, rowLayers.Count());
        }
    }

    //add parent grid to master grid
    PART_MasterGrid.Children.Add(parentGrid);
    Grid.SetRow(parentGrid, 0);
}

Update: I had the following LayeredGrid.xaml and had Generic.xaml to include LayeredGrid.xaml

<Style TargetType="{x:Type common:LayeredGrid}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" LastChildFill="True"
                           Name="PART_ParentPanel">
                    <StackPanel Name="PART_BottomCnt1" Orientation="Horizontal" DockPanel.Dock="Bottom" Background="AliceBlue"></StackPanel>
                    <StackPanel Name="PART_LeftCnt1" Orientation="Horizontal" DockPanel.Dock="Left" Background="AliceBlue">
                        <StackPanel.LayoutTransform>
                            <RotateTransform Angle="90"/>
                        </StackPanel.LayoutTransform>
                    </StackPanel>
                    <StackPanel Name="PART_RightCnt1" Orientation="Horizontal" DockPanel.Dock="Right" Background="AliceBlue">
                        <StackPanel.LayoutTransform>
                            <RotateTransform Angle="90"/>
                        </StackPanel.LayoutTransform>
                    </StackPanel>
                    <Grid Name="PART_MasterGrid" IsSharedSizeScope="True" Background="AliceBlue"></Grid>
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Update2: [Update2 has nothing to do with the above code as this version has Themes as a Root folder] In MainWindow.xaml gives a compiled error Cannot locate resource 'layeredgrid.xaml'. enter image description here

<DockPanel>
    <StackPanel Name="DownStatusBar" DockPanel.Dock="Bottom" Background="AliceBlue">
        <Label></Label>
    </StackPanel>
    <testNest3:LayeredGrid>
        <testNest3:LayeredGrid.Layers>
            <testNest3:Layer Level="0">
                <testNest3:Layer.Content>
                    <Grid>
                        ...
                    </Grid>
                </testNest3:Layer.Content>
            </testNest3:Layer>
        </testNest3:LayeredGrid.Layers>
    </testNest3:LayeredGrid>
</DockPanel>

Solution

  • There are a few things you need to check to make sure your default style gets applied:

    1. Make sure you have an assembly-level ThemeInfo attribute and pass in ResourceDictionaryLocation.SourceAssembly for the second argument (genericDictionaryLocation):

      [assembly: ThemeInfo(
          ResourceDictionaryLocation.None,
          ResourceDictionaryLocation.SourceAssembly)]
      
    2. Make sure you have a Themes\generic.xaml resource dictionary in the same assembly as your custom control, with a Build Action of "Page". Note that Themes must be a top-level folder in your project.

    3. Make sure you override the default style key for your custom control in a static constructor:

      static LayerGrid() {
          DefaultStyleKeyProperty.OverrideMetadata(
              typeof(LayerGrid),
              new FrameworkPropertyMetadata(typeof(LayerGrid)));
      }
      
    4. Make sure your generic.xaml includes (either directly or through dictionary merging) a Style with a TargetType matching your custom control. It should not have an explicit x:Key, and it should set the Template property. If you pull your style in through MergedDictionaries, make sure to use assembly-qualified URIs when merging in other dictionaries, e.g.:

      <ResourceDictionary Source="/test_nest3;component\Themes/LayeredGrid.xaml" />
      

    If you've verified everything above and are still having problems, check your output window to make sure there isn't some sort of error happening that might prevent the style from being applied. Also, check the obvious: is the control actually getting loaded into the visual tree somewhere?


    EDIT: I was able to open your project on my phone, and it seems your Themes folder is in the wrong location: it must be directly under your project, but you have it nested under a Common folder. The location is supposed to be relative to the assembly root, not the folder containing the file where your control is defined.