Search code examples
c#c#-4.0winui-3winuiuwb

How to change DataTemplate depending on API in WinUI?


I have 6 DataTemplate for this API. API is a enum.

public enum ShimmerType 
{
    CirclePersona,
    SquarePersona,
    Profile,
    Article,
    Video,
    Feed,
    Shopping,
}

API name is Type. I defined this property in below of my shimmer control.

public ShimmerType Type
{
    get { return (ShimmerType)GetValue(TypeProperty); }
    set { SetValue(TypeProperty, value); }
}

// Using a DependencyProperty as the backing store for Type.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(ShimmerType), typeof(SfShimmer), new PropertyMetadata(ShimmerType.CirclePersona,OnTypePropertyChangedMethod));

In my ShimmerControl.XAML:

I have given a sample data template for your understanding.

<DataTemplate x:Key="ShimmerFeedTemplate">
    <!--Blah Blah blah -->
</DataTemplate>
<DataTemplate x:Key="ShimmerCirclePersonaTemplate">
    <!--Blah Blah blah -->
</DataTemplate>
<DataTemplate x:Key="ShimmerArticleStyle">
    <!--Blah Blah blah -->
</DataTemplate>
<DataTemplate x:Key="ShimmerProfileTemplate">
    <!--Blah Blah blah -->
</DataTemplate>
<DataTemplate x:Key="ShimmerShoppingTemplate">
    <!--Blah Blah blah -->
</DataTemplate>
<DataTemplate x:Key="ShimmerVideoTemplate">
    <!--Blah Blah blah -->
</DataTemplate>

Shimmer Style:

I've given you a control templates in the Shimmer style. I have provided content template as CirclePersona template by with shimmer control.

<Style x:Key="ShimmerStyle" TargetType="local:Shimmer">
    <Setter Property="HorizontalAlignment" Value="Center"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Fill" Value="{ThemeResource ShimmerFillColor}"/>
    <Setter Property="Template"> 
        <Setter.Value>
            <ControlTemplate TargetType="local:Shimmer">
                <StackPanel>
                    <ContentControl x:Name="Grid1">
                        <ContentPresenter x:Name="presenters" ContentTemplate="{StaticResource ShimmerCirclePersonaTemplate}" />
                    </ContentControl>
                    <Grid x:Name="Grid2">
                        <ContentControl>
                            <ContentPresenter Content="{TemplateBinding Content}"/>
                        </ContentControl>
                    </Grid>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

How to change the DataTemplate of my Control ContentPresenter to according the Type API .I have set a separate datatemplate for each enum type API.

I have Try below this:

public class SfShimmer:Control
{
    public SfShimmer()                                   
    {
        this.DefaultStyleKey= typeof(SfShimmer);
    }
       
    internal ContentPresenter Presenter;

    public ShimmerType Type
    {
        get { return (ShimmerType)GetValue(TypeProperty); }
        set { SetValue(TypeProperty, value); }
    }

    public static readonly DependencyProperty TypeProperty =
        DependencyProperty.Register("Type", typeof(ShimmerType), typeof(SfShimmer), new PropertyMetadata(ShimmerType.CirclePersona,OnTypePropertyChangedMethod));

    protected override void OnApplyTemplate()
    {  
        this.Presenter = this.GetTemplateChild("presenters") as ContentPresenter;
        base.OnApplyTemplate();
        this.Loaded += SfShimmer_Loaded;
    }
 
    private static void OnTypePropertyChangedMethod(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SfShimmer sfShimmer = d as SfShimmer;
        ContentPresenter pr = sfShimmer.Presenter;
        if (pr != null)
        {
            DataTemplate dataTemplate = null;
            switch (sfShimmer.Type)
            {
                case ShimmerType.Feed:
                    dataTemplate = sfShimmer.Resources["ShimmerFeedControlTemplate"] as DataTemplate;
                    break;
                case ShimmerType.Profile:
                    dataTemplate = sfShimmer.Resources["ShimmerProfileTemplate"] as DataTemplate;
                    break;
                case ShimmerType.Video:
                    dataTemplate = sfShimmer.Resources["ShimmerVideoTemplate"] as DataTemplate;
                    break;
                case ShimmerType.Shopping:
                    dataTemplate = sfShimmer.Resources["ShimmerShoppingTemplate"] as DataTemplate;
                    break;
                default:
                    dataTemplate = sfShimmer.Resources["ShimmerFeedControlTemplate"] as DataTemplate;
                    break;
            }
            pr.ContentTemplate = dataTemplate;
        }
    }
}

I tried this but no progress. In WinUI MainWindow.Xaml I specified this API like below:

<Window
    x:Class="WinUI_3_SFShimmer_control.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUI_3_SFShimmer_control"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:shim="using:Shimmer.WinUI">

    <Grid>
        <shim:Shimmer x:Name="shimmer" Type="Profile" />
    </Grid>
</Window>    

The dataTemplate should be the same as the contenttemplate of my content control, depending on what type I give to my Type API in the mainwindow.xaml. How in WinUI C#?


Solution

  • You can create yourown DataTemplateSelector.

    This is a simple example based on a bit of your code:

    public enum ShimmerType
    {
        CirclePersona,
        SquarePersona,
        Profile,
    }
    
    public class ShimmerTemplateSelector : DataTemplateSelector
    {
        public DataTemplate? CirclePersonaTemplate { get; set; }
    
        public DataTemplate? SquarePersonaTemplate { get; set; }
    
        public DataTemplate? ProfileTemplate { get; set; }
    
        protected override DataTemplate? SelectTemplateCore(object item)
        {
            return (item as CustomButton)?.ShimmerType switch
            {
                ShimmerType.CirclePersona => CirclePersonaTemplate,
                ShimmerType.SquarePersona => SquarePersonaTemplate,
                ShimmerType.Profile => ProfileTemplate,
                _ => base.SelectTemplateCore(item),
            };
        }
    }
    
    public class CustomButton : Button
    {
        public static readonly DependencyProperty ShimmerTypeProperty =
            DependencyProperty.Register(
                nameof(ShimmerType),
                typeof(ShimmerType),
                typeof(CustomButton),
                new PropertyMetadata(ShimmerType.CirclePersona, OnShimmerTypePropertyChanged));
    
        public ShimmerType ShimmerType
        {
            get => (ShimmerType)GetValue(ShimmerTypeProperty);
            set => SetValue(ShimmerTypeProperty, value);
        }
    
        private static void OnShimmerTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is CustomButton button)
            {
                button.ContentTemplate = button.ContentTemplateSelector.SelectTemplate(button);
            }
        }
    }
    
    <MainWindow
    ...
    ...>
    
        <Grid>
            <Grid.Resources>
                <DataTemplate x:Key="CirclePersonaDataTemplate">
                    <TextBlock Text="CirclePersona" />
                </DataTemplate>
                <DataTemplate x:Key="SquarePersonaDataTemplate">
                    <TextBlock Text="SquarePersona" />
                </DataTemplate>
                <DataTemplate x:Key="ProfileDataTemplate">
                    <TextBlock Text="Profile" />
                </DataTemplate>
                <local:ShimmerTemplateSelector
                    x:Key="ShimmerTemplateSelector"
                    CirclePersonaTemplate="{StaticResource CirclePersonaDataTemplate}"
                    ProfileTemplate="{StaticResource ProfileDataTemplate}"
                    SquarePersonaTemplate="{StaticResource SquarePersonaDataTemplate}" />
            </Grid.Resources>
    
            <Grid>
                <local:CustomButton
                    Content="?"
                    ContentTemplateSelector="{StaticResource ShimmerTemplateSelector}"
                    ShimmerType="Profile" />
            </Grid>
        </Grid>
    </MainWindow>