Search code examples
c#xamluwpwin-universal-appcontroltemplate

Accessing ControlTemplate Style In Custom Application.Resources


I have created a template style for a button that I would like to call for each album in my project.

<Application.Resources>
    <Style x:Key="CustomButtonLarge" TargetType="Button">
        <Setter Property="Background" Value="Pink" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="Width" Value="300" />
        <Setter Property="Height" Value="100" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="Height" Value="300" />
        <Setter Property="Width" Value="200" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid x:Name="AlbumContentGrid">

                        <Grid.RowDefinitions>
                            <RowDefinition Height="200"/>
                            <RowDefinition Height="50"/>
                            <RowDefinition Height="50"/>
                        </Grid.RowDefinitions>

                        <Image Grid.Row="0" source="null" x:Key="albumCover" />
                        <Textblock Grid.Row="1" x:Key="Title" Style="{StaticResources CustomForegroundTitleText}"/>
                        <Textblock Grid.Row="2" x:Key="SubTitle" Style="{StaticResources CustomForegroundSubTitleText}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


</Application.Resources>

When I am in the code behind I want to create this button for each album. So if there is 3 albums, I would like to do a for loop...

int numberOfButtons= 3;

private void Page_Loaded(object sender, RoutedEventArgs e)
    {

        for (int i = 0; i < numberOfButtons; i++)
        {
            Button btn = new Button();
            Style style = App.Current.Resources["CustomButtonLarge"] as Style;

            btn.Style = style;

            StackAlbums.Children.Add(btn);
        }

    }

StackAlbums being a stackPanel in the main grid. For some reason I am not getting anything when I run.

But I'm also not sure how to access the "albumCover" Image so that I can change the source to whatever I need it to be in the code and Change the text values of the Title and SubTitle Textblocks.


Solution

  • The first, you should fix the Style that the Style has the duplicate property width and Height.

    Then you should make the effect for Background. You should bind it to Grid.

                        <Grid x:Name="AlbumContentGrid" Background="{TemplateBinding Background}" >
    

    The Grid should be set the Background to bind the Button background.

    And you should remove all the x:Key.

    If you want to set the Image in code that you should make the data context.

    I make a class Foo to do it.

    public class Foo
    {
        public BitmapImage Image { get; set; }
    
        public string Title { get; set; }
    
        public string  SubTitle { get; set; }
    }
    

    And I should set it when adding the button.

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            int numberOfButtons = 3;
    
    
            for (int i = 0; i < numberOfButtons; i++)
            {
                var foo = new Foo
                {
                    Image = new BitmapImage(new Uri("ms-appx:///Assets/Square44x44Logo.scale-200.png")),
                    Title = "title" + i,
                    SubTitle = i.ToString()
                };
    
                Button btn = new Button();
                Style style = Application.Current.Resources["CustomButtonLarge"] as Style;
    
                btn.Style = style;
    
                btn.DataContext = foo;
    
                StackAlbums.Children.Add(btn);
            }
        }
    

    The code uses Square44x44Logo.scale-200.png and you can change it.

    Then I should use bind to bind the data context and all the code for CustomButtonLarge is

    <Application.Resources>
        <Style x:Key="CustomButtonLarge" TargetType="Button">
            <Setter Property="Background" Value="Black" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="Margin" Value="10,10,10,10"></Setter>
            <Setter Property="Height" Value="200" />
            <Setter Property="Width" Value="100" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button" >
                        <Grid x:Name="AlbumContentGrid" Background="{TemplateBinding Background}" >
                            <Grid.RowDefinitions>
                                <RowDefinition Height="200*"/>
                                <RowDefinition Height="50*"/>
                                <RowDefinition Height="50*"/>
                            </Grid.RowDefinitions>
    
                            <Image Grid.Row="0" x:Name="AlbumCover" Source="{Binding Path=Image}"/>
                            <TextBlock Grid.Row="1" x:Name="Title" Text="{Binding Title}" Foreground="{TemplateBinding Foreground}"/>
                            <TextBlock Grid.Row="2" x:Name="SubTitle" Text="{Binding SubTitle}" Foreground="{TemplateBinding Foreground}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>
    

    I try to run it and clip the screen to you.

    enter image description here

    If you want to add the click event that you should add some code.

            for (int i = 0; i < numberOfButtons; i++)
            {
                var foo = new Foo
                {
                    Image = new BitmapImage(new Uri("ms-appx:///Assets/Square44x44Logo.scale-200.png")),
                    Title = "title" + i,
                    SubTitle = i.ToString()
                };
    
                Button btn = new Button();
                Style style = Application.Current.Resources["CustomButtonLarge"] as Style;
    
                btn.Style = style;
    
                btn.DataContext = foo;
    
                StackAlbums.Children.Add(btn);
    
                btn.Click += Button_OnClick; // Make the click
            }
    

    And you should write Button_OnClick and add break point to know the user click the button.

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine(StackAlbums.Children.Count);
            Debug.WriteLine((StackAlbums.Children[0] as FrameworkElement)?.ActualWidth );
            Debug.WriteLine((StackAlbums.Children[0] as Button)?.Background?.ToString() ?? "");
        }
    

    enter image description here

    Edit

    If you want to add click animation that you should add the code to VisualStateManager.VisualStateGroups.

                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <PointerUpThemeAnimation Storyboard.TargetName="AlbumContentGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AlbumContentGrid"
                                                                       Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0"
                                                                    Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Title"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0"
                                                                    Value="#aaaaaa" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SubTitle"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0"
                                                                    Value="#aaaaaa" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <PointerUpThemeAnimation Storyboard.TargetName="AlbumContentGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AlbumContentGrid"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AlbumContentGrid"
                                                                       Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Title"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SubTitle"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <PointerDownThemeAnimation Storyboard.TargetName="AlbumContentGrid" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
    

    You should add the code to AlbumContentGrid like this figure.

    enter image description here

    You can see the click animation when you add the code.

    enter image description here