1

I'm trying to create a custom button for a small icon An icon in a small green button but the button only show when i'm refreshing it in the xaml code or resizing window. Do you know how to make it show at the initiation of the page? Or do it in better way?

I'm using a custom control to use like

<customcontrol:IconButton Width="100" Height="100"
     iconCode="&#xE716;" 
     Type="AddButtonStyle"/>

the IconButton Class :

    /// <summary>
    /// Custom Control for an icon in a small button
    /// </summary>
    public sealed partial class IconButton : Button
    {
        /// <summary>
        /// icon code to add to the button
        /// </summary>
        public string IconCode { get; set; } = string.Empty;
        /// <summary>
        /// Type of the Style to apply on the Button 
        /// </summary>
        public CustomButtonType Type { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public IconButton()
        {
            this.DefaultStyleKey = typeof(IconButton);
        }
        /// <summary>
        /// 
        /// </summary>
        protected override void OnApplyTemplate()
        {
            try
            {
                base.OnApplyTemplate();
            }catch
            {
                Console.WriteLine("error base.OnApplyTemplate");
            }
            try
            {
                switch (Type)
                {
                    case CustomButtonType.AccentButtonStyle:
                        this.Style = FournierStyles.MainStyles["AccentButtonStyle"] as Style;
                        break;
                    case CustomButtonType.AddButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["AddButtonStyle"] as Style;
                        break;
                    case CustomButtonType.PrincipalButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["PrincipalButtonStyle"] as Style;
                        break;
                    case CustomButtonType.DangerButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["DangerButtonStyle"] as Style;
                        break;
                    case CustomButtonType.SecondaryButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["SecondaryButtonStyle"] as Style;
                        break;
                    case CustomButtonType.WarningButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["WarningButtonStyle"] as Style;
                        break;
                    case CustomButtonType.InfoButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["InfoButtonStyle"] as Style;
                        break;
                    case CustomButtonType.SucessButtonStyle:
                        this.Style = FournierStyles.ButtonStyles["SucessButtonStyle"] as Style;
                        break;
                    case CustomButtonType.DefaultButtonStyle:
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                throw new StyleTypeException("Impossible to set Style to button for " + ex);
            }
            try
            {
                FontIcon icon = new()
                {
                    Glyph = IconCode,
                    Foreground = new SolidColorBrush(Colors.Black)
                };
                this.Content = icon;
                this.UpdateLayout();
                this.Width = 30;
                this.Height = 30;
            }
            catch (Exception ex)
            {
                throw new IconButtonGenerationException("Impossible to creation icon to IconButton because " + ex);
            }
        }
    }

The IconButton Class will be use to get input for CRUD modification.

0

2 Answers 2

2

The properties of your IconButton class should be dependency properties, which provide PropertyChangedCallbacks that modify the IconButton instance when their value changes.

You may also want to bind the FontSize property of the FontIcon in the Button's Content to the FontSize property of the Button.

public sealed partial class IconButton : Button
{
    public IconButton()
    {
        DefaultStyleKey = typeof(IconButton);

        var icon = new FontIcon();
        var fontSizeBinding = new Binding
        {
            Source = this,
            Path = new PropertyPath(nameof(FontSize))
        };

        icon.SetBinding(FontIcon.FontSizeProperty, fontSizeBinding);
        Content = icon;
    }

    public static readonly DependencyProperty IconCodeProperty =
        DependencyProperty.Register(
            nameof(IconCode), typeof(string), typeof(IconButton),
            new PropertyMetadata(null, IconCodePropertyChanged));

    public static readonly DependencyProperty TypeProperty =
        DependencyProperty.Register(
            nameof(Type), typeof(CustomButtonType), typeof(IconButton),
            new PropertyMetadata(null, TypePropertyChanged));

    public string IconCode
    {
        get => (string)GetValue(IconCodeProperty);
        set => SetValue(IconCodeProperty, value);
    }

    public CustomButtonType Type
    {
        get => (CustomButtonType)GetValue(TypeProperty);
        set => SetValue(TypeProperty, value);
    }

    private static void IconCodePropertyChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var button = (IconButton)obj;
        var icon = (FontIcon)button.Content;
        icon.Glyph = (string)args.NewValue;
    }

    private static void TypePropertyChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var button = (IconButton)obj;
        var type = (CustomButtonType)args.NewValue;
        button.Style = FournierStyles.ButtonStyles[type.ToString()] as Style;
    }
}

Not sure if as Style is really needed when accessing the ButtonStyles dictionary. It should actually be something like Dictionary<string, Style> ButtonStyles { get; }. Or even Dictionary<CustomButtonType, Style> ButtonStyles { get; }, in which case the TypePropertyChanged callback would be

private static void TypePropertyChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
    var button = (IconButton)obj;
    var type = (CustomButtonType)args.NewValue;
    button.Style = FournierStyles.ButtonStyles[type];
}

Besides that, it seems questionable whether declaring the Type property makes sense at all, when instead of

<customcontrol:IconButton... Type="AddButtonStyle"/>

you could as well write

<customcontrol:IconButton... Style="{StaticResource AddButtonStyle}"/>

where AddButtonStyle would be an appropriate Style resource in XAML.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, your answer is really clear. For the FournierStyles.ButtonStyles I've declare it as ResourceDictionary _ButtonStyles = Application.Current.Resources.MergedDictionaries.Where(md => md.Source.OriginalString.Equals("pathToXaml")).FirstOrDefault(); I like the Enum system so it can autocomplete the available style to the developper even if the dictionnary is not merged. Maybe I'll change it so the dev can override it in the different use case.
You're right it would be great to have Dictionary<CustomButtonType, Style> ButtonStyles { get; } instead of ResourceDictionary _ButtonStyles
2

I would hide the original Content property and add a new one but of the type string then use it instead of IconCode.

In the code below, I also added registered for font size changes:

IconButton.xaml

public sealed partial class IconButton : Button
{
    public static new readonly DependencyProperty ContentProperty =
        DependencyProperty.Register(
            nameof(Content),
            typeof(string),
            typeof(IconButton),
            new PropertyMetadata(default, OnContentPropertyChanged));

    public IconButton()
    {
        DefaultStyleKey = typeof(IconButton);
        Loaded += IconButton_Loaded;
        _ = RegisterPropertyChangedCallback(FontSizeProperty, OnFontSizePropertyChanged);
    }

    public new string Content
    {
        get => (string)GetValue(ContentProperty);
        set => SetValue(ContentProperty, value);
    }

    private static void OnContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not IconButton iconButton ||
            e.NewValue is not string content)
        {
            return;
        }

        iconButton.SetContent(content);
    }

    private void IconButton_Loaded(object sender, RoutedEventArgs e)
    {
        ApplyFontSize();
    }

    private void OnFontSizePropertyChanged(DependencyObject sender, DependencyProperty dp)
    {
        ApplyFontSize();
    }

    private void SetContent(string content)
    {
        base.Content = content;
    }

    private void ApplyFontSize()
    {
        if (base.ContentTemplateRoot is not FontIcon fontIcon)
        {
            return;
        }

        fontIcon.FontSize = FontSize;
    }
}

Themes/Generic.xaml

<Style BasedOn="{StaticResource DefaultIconButtonStyle}" TargetType="local:IconButton" />

<Style x:Key="DefaultIconButtonStyle"
    BasedOn="{StaticResource DefaultButtonStyle}"
    TargetType="local:IconButton">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
        <FontIcon Glyph="{Binding}" />
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

How to use it:

<Page.Resources>
    <Style x:Key="BlueIconButtonStyle"
        BasedOn="{StaticResource DefaultIconButtonStyle}"
        TargetType="local:IconButton">
        <Setter Property="Background" Value="Blue" />
    </Style>
</Page.Resources>

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <local:IconButton
        Content="&#xE716;"
        FontSize="24" />
    <local:IconButton
        Content="&#xE716;"
        Style="{StaticResource BlueIconButtonStyle}" />
</StackPanel>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.