Gabor Miklos Gabor Miklos - 3 years ago 326
C# Question

Wpf Custom button icon and text change from code

So I'm gonna be short. I would like to set the textBlock (x:Name="ButtonText") and Images (x:Name="LeftIcon" and x:Name="RightIcon") from code in another Project using the compiled .dll from this.

XAML:

<Button x:Class="myClass.actionButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="ActionButton">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="button" CornerRadius="10" BorderBrush="#F555" BorderThickness="1.5">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#CC323232" Offset="0"/>
<GradientStop Color="#CC4B4B4B" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="24"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="24"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="ButtonText" Grid.Column="1" HorizontalAlignment="Center" TextWrapping="Wrap" Margin="0,0,0,0" VerticalAlignment="Center" Width="auto"/>
<Image x:Name="LeftIcon" Grid.Column="0" HorizontalAlignment="Left" Height="16" Margin="4,1,0,0" VerticalAlignment="Center" Width="16"/>
<Image x:Name="RightIcon" Grid.Column="2" HorizontalAlignment="Right" Height="16" Margin="0,1,4,0" VerticalAlignment="Center" Width="16"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>


CS:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Markup;

namespace myClass
{
public partial class actionButton : Button
{
private TextBlock ButtonText;
private Image LeftIcon;
private Image RightIcon;

public Image leftIcon
{
get { return LeftIcon; }
set { LeftIcon = value; }
}

public Image rightIcon
{
get { return RightIcon; }
set { RightIcon = value; }
}

public TextBlock buttonText
{
get { return ButtonText; }
set { ButtonText = value; }
}

public actionButton()
{
InitializeComponent();
}
}

}


Currently if I append a new textBlock to my button instance from code, it doesn't show up... Same for the images. What am I missing?

Thank you for the help... :)

Answer Source

Your actionButton class should declare bindable dependency properties for the two images and the text.

An example for the left image is shown below. The property type is ImageSource, because that is the type of the Source property of the Image control. You would have to declare a second property for the right image, and a property of type string for the TextBlock text.

public static readonly DependencyProperty LeftImageProperty =
    DependencyProperty.Register(
        nameof(LeftImage), typeof(ImageSource), typeof(actionButton));

public ImageSource LeftImage
{
    get { return (ImageSource)GetValue(LeftImageProperty); }
    set { SetValue(LeftImageProperty, value); }
}

In the Button's XAML, you would use the properties with a RelativeSource Binding:

<TextBlock Text="{Binding Text,
                  RelativeSource={RelativeSource AncestorType=Button}}" ... />
<Image Source="{Binding LeftImage,
                RelativeSource={RelativeSource AncestorType=Button}}" ... />
<Image Source="{Binding RightImage,
                RelativeSource={RelativeSource AncestorType=Button}}" ... />

Since these Bindings are in the Button's Template, you may as well use a TemplateBinding. You would however have to set the appropriate TargetType:

<Button x:Class="MyNamespace.actionButton"
        ...
        xmlns:local="clr-namespace:MyNamespace">
    <Button.Template>
        <ControlTemplate TargetType="local:actionButton">
            ...
            <Image Source="{TemplateBinding LeftImage}" ... />
            ...
        </ControlTemplate>
    </Button.Template>
</Button>

Now when you use your Button, you can simply set (or also bind) these properties like this:

<local:ActionButton x:Name="ab" LeftImage="SomeImage.jpg"/>

or in code behind:

ab.LeftImage = new BitmapImage(new Uri("SomeImage.jpg", UriKind.RelativeOrAbsolute));

If the image file should be embedded as assembly resource, you should set its Build Action to Resource, and load it from a Resource File Pack URI:

ab.LeftImage = new BitmapImage(new Uri("pack://application:,,,/SomeImage.jpg"));

As a note, you should follow widely accepted naming conventions, and call it ActionButton.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download