And so, look at your task, what is required? And we need a button that will have additional values, have its own style, and all this should be comfortable! For such purposes, you can use UserControl. Let's make a similar:
- Click on our project with the right mouse button - Add - User Control - We think over the name and click OK.
- Next we will have almost the same thing as a regular window (.xaml file and next .cs file).
In the .cs file we need to set the DependencyProperty for all the additional properties of our control, we write and we get something like this:
public partial class CustomButton : UserControl { public CustomButton() { InitializeComponent(); } public Visibility DoubleVisibility { get => (Visibility)GetValue(DoubleVisibilityProperty); set => SetValue(DoubleVisibilityProperty, value); } public Brush DoubleBackground { get => (Brush)GetValue(DoubleBackgroundProperty); set => SetValue(DoubleBackgroundProperty, value); } public Brush DoubleForeground { get => (Brush)GetValue(DoubleForegroundProperty); set => SetValue(DoubleForegroundProperty, value); } public string DoubleText { get => (string)GetValue(DoubleTextProperty); set => SetValue(DoubleTextProperty, value); } public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); } public ICommand ButtonCommand { get => (ICommand)GetValue(ButtonCommandProperty); set => SetValue(ButtonCommandProperty, value); } public static readonly DependencyProperty DoubleVisibilityProperty = DependencyProperty.Register("DoubleVisibility", typeof(Visibility), typeof(CustomButton), new PropertyMetadata(Visibility.Visible)); public static readonly DependencyProperty DoubleBackgroundProperty = DependencyProperty.Register("DoubleBackground", typeof(Brush), typeof(CustomButton), new PropertyMetadata(new SolidColorBrush(Color.FromArgb(255, 252, 74, 38)))); public static readonly DependencyProperty DoubleForegroundProperty = DependencyProperty.Register("DoubleForeground", typeof(Brush), typeof(CustomButton), new PropertyMetadata(Brushes.White)); public static readonly DependencyProperty DoubleTextProperty = DependencyProperty.Register("DoubleText", typeof(string), typeof(CustomButton), new PropertyMetadata("0")); public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(CustomButton), new PropertyMetadata("Text")); public static readonly DependencyProperty ButtonCommandProperty = DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(CustomButton), new PropertyMetadata(null)); }
Fine! Now we need to pretend our control. So, as we need a button, let's rewrite the design to it:
<Button Command="{Binding ButtonCommand, ElementName=Control}" CommandParameter="{Binding}"> <Button.Template> <ControlTemplate TargetType="{x:Type Button}"> <Grid> <Grid.Effect> <DropShadowEffect BlurRadius="4" ShadowDepth="0" Direction="-90" Opacity="0.5"/> </Grid.Effect> <Border Name="Mask" Background="White" CornerRadius="7" Margin="5"/> <Border Background="White" Margin="5"> <Border.OpacityMask> <VisualBrush Visual="{Binding ElementName=Mask}"/> </Border.OpacityMask> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <Grid Visibility="{Binding DoubleVisibility, ElementName=Control, FallbackValue=Visible, TargetNullValue=Visible}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="2*"/> </Grid.RowDefinitions> <Grid> <Polygon Points="100,0, 0,100 0,0" Fill="{Binding DoubleBackground, ElementName=Control, FallbackValue=#FC4A26, TargetNullValue=#FC4A26}" Stretch="Uniform" HorizontalAlignment="Left" VerticalAlignment="Top"/> <Viewbox HorizontalAlignment="Left" VerticalAlignment="Top"> <TextBlock Padding="5,5,25,0" Text="{Binding DoubleText, ElementName=Control, StringFormat=x{0}, FallbackValue=x0, TargetNullValue=x0}" Foreground="{Binding DoubleForeground, ElementName=Control, FallbackValue=White, TargetNullValue=White}"/> </Viewbox> </Grid> </Grid> <Viewbox Grid.ColumnSpan="2" Grid.Column="0"> <TextBlock Margin="10" Foreground="#4d4d4d" Text="{Binding Text, ElementName=Control, FallbackValue=Text, TargetNullValue=Text}" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Viewbox> </Grid> </Border> </Grid> </ControlTemplate> </Button.Template> </Button>
The UserControl itself is set by its name property:
Name="Control"
Well, it’s at least three times easier for your task (and maybe even solves it), because you already have a control and instead of editing a button through the code, you can immediately call this control, giving it all the necessary values.
But! I'm not tired of repeating that creating objects through code is not the right approach! WPF is not WinForms, there is a very wonderful thing here - Binding. And the MVVM pattern is a great helper for these all bindings, and it has a very funny rule - “The code shouldn’t know about View (xaml markup)”.
Let me show you the simplest implementation of MVVM, where we will display several buttons we have created:
We need a couple of classes for teams:
public class RelayCommand<T> : ICommand { private Action<T> action; public RelayCommand(Action<T> action) => this.action = action; public bool CanExecute(object parameter) => true; #pragma warning disable CS0067 public event EventHandler CanExecuteChanged; #pragma warning restore CS0067 public void Execute(object parameter) => action((T)parameter); } public class RelayCommand : ICommand { private Action action; public RelayCommand(Action action) => this.action = action; public bool CanExecute(object parameter) => true; #pragma warning disable CS0067 public event EventHandler CanExecuteChanged; #pragma warning restore CS0067 public void Execute(object parameter) => action(); }
Next, we need a class that will describe the properties of our button:
public class ButtonViewModel { public Visibility DoubleVisibility { get; set; } public Brush DoubleBackground { get; set; } public Brush DoubleForeground { get; set; } public string DoubleText { get; set; } public string Text { get; set; } public ICommand Command { get; set; } }
Now we need to make the main class, which will be set as a DataContext, a certain MainViewModel. In it we will create a collection, fill it in and make the handler of our buttons:
public class MainViewModel { public ObservableCollection<ButtonViewModel> Buttons { get; set; } = new ObservableCollection<ButtonViewModel>(); public MainViewModel() { Buttons.Add(new ButtonViewModel { Text = "A", DoubleText = "2", DoubleVisibility = Visibility.Visible, DoubleBackground = Brushes.Green, Command = new RelayCommand<ButtonViewModel>(Clicked) }); Buttons.Add(new ButtonViewModel { Text = "B", DoubleText = "10", DoubleVisibility = Visibility.Visible, Command = new RelayCommand<ButtonViewModel>(Clicked) }); Buttons.Add(new ButtonViewModel { Text = "C", DoubleVisibility = Visibility.Collapsed, Command = new RelayCommand<ButtonViewModel>(Clicked) }); } void Clicked(ButtonViewModel obj) { Console.WriteLine($"Кнопка {obj.Text} нажата!"); } }
We tie the whole thing:
private MainViewModel MainViewModel { get; } = new MainViewModel(); public MainWindow() { InitializeComponent(); DataContext = MainViewModel; }
Well and the last, we create View for this all. ItemsControl is great for this:
<ItemsControl ItemsSource="{Binding Buttons}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <local:CustomButton Width="150" Height="150" ButtonCommand="{Binding Command}" Text="{Binding Text}" DoubleVisibility="{Binding DoubleVisibility}" DoubleBackground="{Binding DoubleBackground}" DoubleForeground="{Binding DoubleForeground}" DoubleText="{Binding DoubleText}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
Fuh, well, everything, time to run and enjoy the result:

Well, that's all, I hope I showed you the proper work with the elements in WPF. Good luck learning!