Search code examples
wpfxamlresourcedictionary

Base XAML Controls on a Resource Control


Is it possible to base one or more controls on a control that is defined in the Resources. So that the controls inherit most properties from the base control. Similar to the Style approach but for some reason I cannot use Events/EventSetter (AutoGeneratingColumns in this case), the error I get is "xy-Event is not a Routed Event"

Here an example of what I want to accomplish. I have datagrids where most of the properties are the same

<DataGrid x:Name="gridEditSystem"
           AutoGeneratingColumn="onGridEditSystem_autoGeneratingColumn"
           SelectionUnit="Cell"
           SelectionMode="Single" CellStyle="{StaticResource GridEditStyle}">
</DataGrid>

<DataGrid x:Name="gridEditPlanets" SelectedCellsChanged="gridEditPlanets_SelectedCellsChanged"
           AutoGeneratingColumn="onGridEditSystem_autoGeneratingColumn"
           SelectionUnit="Cell"
           SelectionMode="Single" CellStyle="{StaticResource GridEditStyle}">
</DataGrid>

What I want now is a "Base Control"

<Window.Resources>
    <DataGrid x:Key="BaseDataGrid" AutoGeneratingColumn="onGridEditSystem_autoGeneratingColumn"
              SelectionMode="Single" SelectionUnit="Cell"
              CellStyle="{StaticResource GridEditStyle}">
    </DataGrid>
</Window.Resources>

And inheriting Controls

 <DataGrid x:Name="gridEditSystem"
           BasedOn/Inherits/Templates={StaticResource BaseDataGrid}
 </DataGrid>

 <DataGrid x:Name="gridEditPlanets" 
           BasedOn/Inherits/Templates={StaticResource BaseDataGrid}
 </DataGrid>

I tried a few combinations but failed so far nor did I find anything on Google. Is this possible in XAML?


Solution

  • You cannot do that, However in WPF you can approch this in many ways.

    You can make a custom grid control with all your common properties, and use it instead of the regular DataGrid control.

        public class BaseDataGrid : DataGrid
        {
            protected override void OnInitialized(EventArgs e)
            { 
                 base.OnInitialized(e);
    
                 // Set all you common properties here
                 SelectionUnit = DataGridSelectionUnit.Cell;
                 SelectionMode = DataGridSelectionMode.Single;
                 CellStyle = FindResource("GridEditStyle") as Style;
             }
        }
    

    in your xaml

            <local:BaseDataGrid x:Name="gridEditSystem"/>
            <local:BaseDataGrid x:Name="gridEditPlanets"/>
    

    You can also make a behavoir with all your common properties and attach it to the DataGrids you want.

         public class BaseGridBehavior : Behavior<DataGrid>
         {
            protected override void OnAttached()
            {
                AssociatedObject.Initialized += AssociatedObject_Initialized;
    
                 base.OnAttached();
            }
    
            void AssociatedObject_Initialized(object sender, EventArgs e)
            {
                // Set all you common properties here
                AssociatedObject.SelectionUnit = DataGridSelectionUnit.Cell;
                AssociatedObject.SelectionMode = DataGridSelectionMode.Single;
                AssociatedObject.CellStyle = AssociatedObject.FindResource("GridEditStyle") as Style;
            }
        }
    

    and in xaml:

            <DataGrid x:Name="gridEditSystem">
                <i:Interaction.Behaviors>
                    <local:BaseGridBehavior/>
                </i:Interaction.Behaviors>
            </DataGrid>
            <DataGrid x:Name="gridEditPlanets">
                <i:Interaction.Behaviors>
                    <local:BaseGridBehavior/>
                </i:Interaction.Behaviors>
            </DataGrid>
    

    This will need you to include and reference the System.Windows.Interactivity dll

    Hope this helps