Search code examples
wpfxamluser-controlscode-reuseresourcedictionary

Split one big XAML in number of Sub-XAML files


In my WPF4 Desktop-based application there is a big block with sidebar menu that repeats in each window and takes about 70 lines of XAML. In order to improve code reuse, I would like to split XAML file in two files:

  1. XAML-file that contains code for sidebar menu (≈70 lines)
  2. Base XAML file that contains «include/reference» to XAML-file with sidebar menu code

As I understood, there are two ways to implement my problem:

  1. Use ResourceDictionary
  2. Use UserControl/CustomControl

My questions:

  1. What is the difference between ResourceDictionary and UserControl? Could you give me examples where I have to use UserControl and where ResourceDictionary?

  2. Could you give a full code example how to include/import content of one XAML-file to other?

P.S. Here is an example of code that I want to export to separate XAML-file:

<Border Style = "{StaticResource Body_SideBarMenu_Border_Settings}">
    <StackPanel Style = "{StaticResource Body_SideBarMenu}">
        <TextBlock Style = "{StaticResource Body_SideBarMenu_Title}"
                   Text = "{x:Static res:Resources.WinApp_SideBarMenu_Title}" />
        <TextBlock x:Name = "SideBar_WinReports"
                   Style = "{StaticResource Body_SideBarMenu_Item}"
                   Text = "{x:Static res:Resources.DashListMarker}">
            <Hyperlink KeyboardNavigation.TabIndex = "12"
                       Style = "{StaticResource Body_SideBarMenu_Item_Hyperlink}"
                       Click = "Call_WinReports_Click">
                <TextBlock Text = "{x:Static res:Resources.WinApp_ModuleName_Reports}" />
            </Hyperlink>
        </TextBlock>
    </StackPanel>
</Border>

Solution

  • ResourceDictionary is just a container for your styles/templates etc. So you really have a choice between using a style (and referencing it through a ResourceDictionary) or a UserControl.

    In order to differentiate between the two, ask yourself a question: are you implementing just another look for some existing control, or you are implementing something really new, which is more than just a ListView (or a Border, or a ComboBox etc.)? In the former case, use a style; in the latter, create a new UserControl.

    Specifically for your case, I would go for a UserControl.


    Code example (although not full)

    (Please note that a template for the following code can be inserted with VS's "add new UserControl")

    Xaml:

    <UserControl x:Class="SomeNamespace.SidebarMenu"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
        <UserControl.Resources> <!-- you can define local styles here -->
            <Style x:Key="SidebarMenuTextblock" TargetType=TextBlock>
                ...
            </Style>
        </UserControl.Resources>
    
        <Border Background=...>
            <StackPanel>
    
                <TextBlock
                    x:Name="Put_a_name_if_you_want_to_reference_this_item_in_code_behind"
                    Style="{StaticResource SidebarMenuTextblock}"
                    Text="{x:Static res:Resources.WinApp_SideBarMenu_Title}" />
    
                ...
    
            </StackPanel>
        </Border>
    
    </UserControl>
    

    .cs:

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace SomeNamespace
    {
        public partial class SidebarMenu : UserControl
        {
            public NumericUpDown()
            {
                InitializeComponent();
            }
            ...
            // define here your properties etc,
        }
    }
    

    Now, you can use the control like that:

    <Window
        x:Class="SomeOtherNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="clr-namespace:SomeNamespace">
    
        <Grid>
            <controls:SidebarMenu PropertyIfYouDefinedOne="SomeValue"/>
            ...
        </Grid>
    
    </Window>