I am writing a simple calculator program in WPF,and used Caliburn.Micro MVVM framework.I defined the UI in XMAL like this
<Button Name="Clear" Grid.Row="0" Grid.Column="0" Style="{StaticResource grey_button}" Content="C"/>
<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource grey_button}" Content="+/-"/>
<Button Name="Remainder" Grid.Row="0" Grid.Column="2" Style="{StaticResource grey_button}" Content="%"/>
<Button Name="Division" Grid.Row="0" Grid.Column="3" Style="{StaticResource blue_button}" Content="÷"/>
<Button Name="Seven" Grid.Row="1" Grid.Column="0" Style="{StaticResource white_button}" Content="7"/>
<Button Name="Eight" Grid.Row="1" Grid.Column="1" Style="{StaticResource white_button}" Content="8"/>
<Button Name="Nine" Grid.Row="1" Grid.Column="2" Style="{StaticResource white_button}" Content="9"/>
<Button Name="Multiply" Grid.Row="1" Grid.Column="3" Style="{StaticResource blue_button}" Content="x"/>
<Button Name="Four" Grid.Row="2" Grid.Column="0" Style="{StaticResource white_button}" Content="4"/>
<Button Name="Five" Grid.Row="2" Grid.Column="1" Style="{StaticResource white_button}" Content="5"/>
<Button Name="Six" Grid.Row="2" Grid.Column="2" Style="{StaticResource white_button}" Content="6"/>
<Button Name="Plus" Grid.Row="2" Grid.Column="3" Style="{StaticResource blue_button}" Content="+"/>
<Button Name="One" Grid.Row="3" Grid.Column="0" Style="{StaticResource white_button}" Content="1">
</Button>
<Button Name="Two" Grid.Row="3" Grid.Column="1" Style="{StaticResource white_button}" Content="2"/>
<Button Name="Three" Grid.Row="3" Grid.Column="2" Style="{StaticResource white_button}" Content="3"/>
<Button Name="Subtract" Grid.Row="3" Grid.Column="3" Style="{StaticResource blue_button}" Content="-" FontSize="25"/>
<Button Name="Dot" Grid.Row="4" Grid.Column="0" Style="{StaticResource white_button}" Content="·"/>
<Button Name="Zero" Grid.Row="4" Grid.Column="1" Style="{StaticResource white_button}" Content="0"/>
<Button Name="Backward" Grid.Row="4" Grid.Column="2" Style="{StaticResource white_button}" Content="x"/>
<Button Name="Equal" Grid.Row="4" Grid.Column="3" Style="{StaticResource blue_button}" Content="="/>
In this way,i actually can handle the click action because of Caliburn naming Conversion as i define One,Two,Three .... method in my ViewModel
public void Zero()
{
Input += "0";
}
public void One(string content)
{
Input += "1";
}
public void Two()
{
Input += "2";
}
public void Three()
{
Input += "3";
}
public void Four()
{
Input += "4";
}
Now i want to handle all input action with one method
public void Input(string content)
{
Input+=content;
}
So i imported Microsoft.Xaml.Behaviors as namespace b in the top of view,and defined the following event in one of my button
<Button Name="One" Grid.Row="3" Grid.Column="0" Style="{StaticResource white_button}" Content="1">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<cal:ActionMessage MethodName="One">
<cal:Parameter Value="{Binding ElementName=One, Path=Content}"></cal:Parameter>
</cal:ActionMessage>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
Problmen: I want to reuse the code about Triggers,and I know i should extract this trigger logic to resouce,and i can used it like this:
<Button Name="One" Style="{StaticResource blue_button}" Content="1" Action={StaticResource InputAction,Parameter=Binding{ElementName=One Path=Content}}/>
<Button Name="Two" Style="{StaticResource blue_button}" Content="2" Action={StaticResource InputAction,Parameter=Binding{ElementName=Two Path=Content}}/>
<Button Name="Three" Style="{StaticResource blue_button}" Content="3" Action={StaticResource InputAction,Parameter=Binding{ElementName=Three Path=Content}}/>
...
<Button Name="Plus" Style="{StaticResource blue_button}" Content="+" Action={StaticResource InputAction,Parameter=Binding{ElementName=Plus Path=Content}}/>
The main way to set the action of the button is to use commands. In a typical Solution with GUI on WPF, it is common to implement the MVVM pattern. In this case, commands are set in the ViewModel. You can pass a parameter to the commands for its further processing. In a very simplified form, I will show you the implementation in which the ViewModel also performs the functions of the Model.
The example uses my implementation of ViewModelBase . You can replace it with any convenient for you. Or, if you are interested in my implementation, you can take it from this repository: https://github.com/INexteR/NewTrade/tree/main/NewTradeSln/ViewModels
using Simplified;
using System.Collections.ObjectModel;
namespace Core2024.SO.huojian.question78746674
{
public class CalculatorViewModel : ViewModelBase
{
public static ReadOnlyCollection<string> ButtonNames { get; }
= Array.AsReadOnly("C, +/-, %, ÷, ✖, +, -, ., =, 🠔, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...Any Names"
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
public CalculatorViewModel()
{
DisplayedValue = "0";
}
public RelayCommand CalculatorCommand => GetCommand<string>(CalculatorExecute, CalculatorCanExecute);
private bool CalculatorCanExecute(string parameter)
=> ButtonNames.Contains(parameter);
public string DisplayedValue { get => Get<string>(); private set => Set(value); }
private void CalculatorExecute(string parameter)
{
string value = DisplayedValue;
switch (parameter)
{
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
if (value == "0")
value = string.Empty;
value = value + parameter;
break;
case "C":
value = "0";
break;
case "+/-":
if (value != "0")
{
if (value[0] == '-')
value = value.Substring(1);
else
value = "-" + value;
}
break;
// Logic of other buttons
default:
break;
}
DisplayedValue = value;
}
}
}
<Window x:Class="Core2024.SO.huojian.question78746674.CalculatorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Core2024.SO.huojian.question78746674"
mc:Ignorable="d"
Title="CalculatorWindow" Height="450" Width="800"
SizeToContent="WidthAndHeight"
DataContext="{DynamicResource vm}">
<Window.Resources>
<local:CalculatorViewModel x:Key="vm"/>
<Style x:Key="base" TargetType="FrameworkElement">
<Setter Property="Margin" Value="5"/>
</Style>
<Style x:Key="button.command" TargetType="Button" BasedOn="{StaticResource base}">
<Setter Property="CommandParameter" Value="{Binding Content, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Command" Value="{Binding CalculatorCommand}"/>
<Setter Property="Padding" Value="15 5"/>
</Style>
<Style x:Key="button.white_button" TargetType="Button" BasedOn="{StaticResource button.command}">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Blue"/>
</Style>
<Style x:Key="button.blue_button" TargetType="Button" BasedOn="{StaticResource button.command}">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="{Binding DisplayedValue, Mode=OneWay}" Style="{StaticResource base}" IsReadOnly="True"
HorizontalContentAlignment="Right"
Padding="15 5"/>
<UniformGrid Columns="4">
<Button Style="{StaticResource button.blue_button}" Content="C"/>
<Button Style="{StaticResource button.blue_button}" Content="+/-"/>
<Button Style="{StaticResource button.blue_button}" Content="%"/>
<Button Style="{StaticResource button.blue_button}" Content="÷"/>
<Button Style="{StaticResource button.white_button}" Content="7"/>
<Button Style="{StaticResource button.white_button}" Content="8"/>
<Button Style="{StaticResource button.white_button}" Content="9"/>
<Button Style="{StaticResource button.blue_button}" Content="✖"/>
<Button Style="{StaticResource button.white_button}" Content="4"/>
<Button Style="{StaticResource button.white_button}" Content="5"/>
<Button Style="{StaticResource button.white_button}" Content="6"/>
<Button Style="{StaticResource button.blue_button}" Content="+"/>
<Button Style="{StaticResource button.white_button}" Content="1"/>
<Button Style="{StaticResource button.white_button}" Content="2"/>
<Button Style="{StaticResource button.white_button}" Content="3"/>
<Button Style="{StaticResource button.blue_button}" Content="-" FontSize="25"/>
<Button Style="{StaticResource button.white_button}" Content="·"/>
<Button Style="{StaticResource button.white_button}" Content="0"/>
<Button Style="{StaticResource button.blue_button}" Content="🠔"/>
<Button Style="{StaticResource button.blue_button}" Content="="/>
</UniformGrid>
</StackPanel>
</Window>