Browse Source

add calc app for debugging.

debug-wasm-clicks
Dan Walmsley 3 years ago
parent
commit
133c4a9e6e
  1. 7
      Avalonia.sln
  2. 18
      samples/Calc/App.axaml
  3. 36
      samples/Calc/App.axaml.cs
  4. BIN
      samples/Calc/Assets/avalonia-logo.ico
  5. 16
      samples/Calc/Calc.csproj
  6. 29
      samples/Calc/Models/Calculation.cs
  7. 112
      samples/Calc/Models/Calculator.cs
  8. 159
      samples/Calc/Models/MyStringBuilder.cs
  9. 9
      samples/Calc/Models/Operator.cs
  10. 20
      samples/Calc/Models/OperatorChar.cs
  11. 28
      samples/Calc/ViewLocator.cs
  12. 207
      samples/Calc/ViewModels/MainWindowViewModel.cs
  13. 8
      samples/Calc/ViewModels/ViewModelBase.cs
  14. 377
      samples/Calc/Views/MainView.axaml
  15. 25
      samples/Calc/Views/MainView.axaml.cs
  16. 16
      samples/Calc/Views/MainWindow.axaml
  17. 12
      samples/Calc/Views/MainWindow.axaml.cs
  18. 3
      samples/ControlCatalog.Blazor.Web/App.razor.cs
  19. 4
      samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj
  20. 2
      src/Avalonia.Controls/Button.cs

7
Avalonia.sln

@ -229,6 +229,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Blazor.Web",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.Web", "samples\ControlCatalog.Web\ControlCatalog.Web.csproj", "{8B3E8405-DE18-4048-A459-9CA4AC3319A2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calc", "samples\Calc\Calc.csproj", "{5AE1651A-B97A-40F8-B094-646A9EDCE09A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -539,6 +541,10 @@ Global
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B3E8405-DE18-4048-A459-9CA4AC3319A2}.Release|Any CPU.Build.0 = Release|Any CPU
{5AE1651A-B97A-40F8-B094-646A9EDCE09A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5AE1651A-B97A-40F8-B094-646A9EDCE09A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5AE1651A-B97A-40F8-B094-646A9EDCE09A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5AE1651A-B97A-40F8-B094-646A9EDCE09A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -603,6 +609,7 @@ Global
{62D392C9-81CF-487F-92E8-598B2AF3FDCE} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{6A710364-AE6D-40BD-968B-024311527AC2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{8B3E8405-DE18-4048-A459-9CA4AC3319A2} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{5AE1651A-B97A-40F8-B094-646A9EDCE09A} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

18
samples/Calc/App.axaml

@ -0,0 +1,18 @@
<Application
x:Class="Calc.App"
xmlns="https://github.com/avaloniaui"
xmlns:local="using:Calc"
xmlns:themes="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
<Application.Styles>
<themes:MaterialTheme
BaseTheme="Dark"
PrimaryColor="DeepPurple"
SecondaryColor="Lime" />
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
</Application.Styles>
</Application>

36
samples/Calc/App.axaml.cs

@ -0,0 +1,36 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Calc.ViewModels;
using Calc.Views;
namespace Calc
{
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel()
};
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView)
{
singleView.MainView = new MainView
{
DataContext = new MainWindowViewModel()
};
}
base.OnFrameworkInitializationCompleted();
}
}
}

BIN
samples/Calc/Assets/avalonia-logo.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

16
samples/Calc/Calc.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<PackageReference Include="Material.Avalonia" Version="3.0.0-avalonia11-preview2" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.2.0" />
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

29
samples/Calc/Models/Calculation.cs

@ -0,0 +1,29 @@
using System.IO;
namespace Calc.Models;
public class Calculation
{
private readonly double _firstValue;
private readonly double _secondValue;
private readonly Operator? _operator;
public Calculation(double firstValue, double secondValue, Operator? @operator)
{
_firstValue = firstValue;
_secondValue = secondValue;
_operator = @operator;
}
public double Calculate()
{
return _operator switch
{
Operator.Add => _firstValue + _secondValue,
Operator.Subtract => _firstValue - _secondValue,
Operator.Multiply => _firstValue * _secondValue,
Operator.Divide => _firstValue / _secondValue,
_ => throw new InvalidDataException("Operator not allowed")
};
}
}

112
samples/Calc/Models/Calculator.cs

@ -0,0 +1,112 @@
using System;
using System.Globalization;
namespace Calc.Models;
public static class Calculator
{
public static string Calculate(string str)
{
var calculus = new MyStringBuilder(str);
var numberOfOpeningParentheses = calculus.Count('(');
var numberOfClosingParentheses = calculus.Count(')');
if (numberOfOpeningParentheses != numberOfClosingParentheses)
return "Waiting until all parentheses are closed";
CalculateParentheses(ref calculus);
CalculateNonParentheses(ref calculus);
return calculus.ToString();
}
private static Operator? CharToOperator(char? character)
{
return character switch
{
OperatorChar.Add => Operator.Add,
OperatorChar.Subtract => Operator.Subtract,
OperatorChar.Multiply => Operator.Multiply,
OperatorChar.Divide => Operator.Divide,
_ => null
};
}
private static void CalculateNonParentheses(ref MyStringBuilder calculus)
{
int indexOfOperator;
// Search calculations with precedence first. When there isn't more, continue with the others
while ((indexOfOperator = calculus.IndexOfAny(OperatorChar.PrecedentOperators, 1)) > 0 ||
(indexOfOperator = calculus.IndexOfAny(OperatorChar.NonPrecedentOperators, 1)) > 0)
{
// ==== Find the first operand ==== //
var indexOfPreviousOperator = SetIndexOfPreviousOperator(calculus, indexOfOperator);
var stringOfFirstValue = calculus[(indexOfPreviousOperator + 1)..indexOfOperator];
var startIndexOfCalculation = indexOfPreviousOperator + 1;
// First value could be just the sign -, e.g. in --3
if (stringOfFirstValue.Length == 1 &&
OperatorChar.IsAnOperator(stringOfFirstValue[0]))
{
stringOfFirstValue = "0";
indexOfOperator--; // This way operator would be - and secondValue -3
}
// ==== Find the second operand ==== //
// startIndex = indexOfOperator + 2 avoids to detect sign of second value as operator
var indexOfNextOperator = calculus.IndexOfAny(OperatorChar.Operators, indexOfOperator + 2);
if (indexOfNextOperator == -1) // Last calculation
indexOfNextOperator = calculus.Length;
var stringOfSecondValue = calculus[(indexOfOperator + 1)..indexOfNextOperator];
var nextIndexAfterCalculation = indexOfNextOperator;
// ==== Construct the calculation ==== //
var firstValue = Convert.ToDouble(stringOfFirstValue);
var @operator = CharToOperator(calculus[indexOfOperator]);
var secondValue = Convert.ToDouble(stringOfSecondValue);
var calculation = new Calculation(firstValue, secondValue, @operator);
// Replace calculation with its result
calculus.Replace(startIndexOfCalculation, nextIndexAfterCalculation,
Convert.ToString(calculation.Calculate(), CultureInfo.CurrentCulture));
}
}
private static void CalculateParentheses(ref MyStringBuilder calculus)
{
int indexOfOpeningParenthesis;
while ((indexOfOpeningParenthesis = calculus.LastIndexOf('(')) != -1)
{
var indexOfClosingParenthesis = calculus.IndexOf(')', indexOfOpeningParenthesis);
// Replace parentheses with its result
calculus.Replace(indexOfOpeningParenthesis, indexOfClosingParenthesis + 1,
Calculate(calculus[(indexOfOpeningParenthesis + 1)..indexOfClosingParenthesis]));
}
}
private static int SetIndexOfPreviousOperator(MyStringBuilder calculus, int indexOfOperator)
{
var indexOfPreviousOperator = calculus.LastIndexOfAny(OperatorChar.Operators, indexOfOperator - 1);
// First calculation. There could not be an operator at the beginning, it must be a sign
if (indexOfPreviousOperator == 0)
{
indexOfPreviousOperator = -1;
}
// If the first value is negative and not the first calculation, an operator must be just before the index
// previously calculated as the indexOfPreviousOperator, e.g. in a+-b/c the - isn't previousOperator, it's +
else if (indexOfPreviousOperator > 0 &&
calculus[indexOfPreviousOperator].Equals(OperatorChar.Subtract) && // minus sign
OperatorChar.IsAnOperator(calculus[indexOfPreviousOperator - 1])) // previous index contains an operator
{
indexOfPreviousOperator--;
}
return indexOfPreviousOperator;
}
}

159
samples/Calc/Models/MyStringBuilder.cs

@ -0,0 +1,159 @@
using System;
using System.Text;
namespace Calc.Models;
public sealed class MyStringBuilder
{
private readonly StringBuilder _stringBuilder = new();
public int Length => _stringBuilder.Length;
public char this[int index] => _stringBuilder[index];
public char this[Index index] => _stringBuilder[index];
public string this[Range range] {
get
{
var chain = new MyStringBuilder();
for (var i = range.Start.Value; i < range.End.Value; i++)
{
chain.Append(this[i]);
}
return chain.ToString();
}
}
public MyStringBuilder(){}
public MyStringBuilder(string s)
{
_stringBuilder.Append(s);
}
public override string ToString()
{
return _stringBuilder.ToString();
}
public MyStringBuilder Append<T>(T stuff)
{
_stringBuilder.Append(stuff);
return this;
}
public MyStringBuilder Clear()
{
_stringBuilder.Clear();
return this;
}
public int Count(char character)
{
char[] chars = { character };
return Count(chars);
}
public int Count(char[] chars)
{
var count = 0;
var i = 0;
while (i < Length)
{
foreach (var character in chars)
{
if (this[i].Equals(character))
{
count++;
break;
}
}
i++;
}
return count;
}
public int IndexOf(char character, int startIndex = 0)
{
char[] chars = { character };
return IndexOfAny(chars, startIndex);
}
public int IndexOfAny(char[] chars, int startIndex = 0)
{
var i = startIndex;
while (i >= 0 && i < Length)
{
foreach (var character in chars)
{
if (this[i].Equals(character))
return i;
}
i++;
}
return -1;
}
public MyStringBuilder Insert<T>(int index, T stuff)
{
_stringBuilder.Insert(index, stuff);
return this;
}
public int LastIndexOf(char character)
{
return LastIndexOf(character, Length - 1);
}
public int LastIndexOf(char character, int startIndex)
{
char[] chars = { character };
return LastIndexOfAny(chars, startIndex);
}
public int LastIndexOfAny(char[] chars)
{
return LastIndexOfAny(chars, Length - 1);
}
public int LastIndexOfAny(char[] chars, int startIndex)
{
var i = startIndex;
while (i >= 0 && i < Length)
{
foreach (var character in chars)
{
if (this[i].Equals(character))
return i;
}
i--;
}
return -1;
}
public MyStringBuilder Remove(int index, int length = 1)
{
_stringBuilder.Remove(index, length);
return this;
}
public MyStringBuilder Replace<T>(int startIndex, int endIndex, T replacement)
{
Remove(startIndex, endIndex - startIndex)
.Insert(startIndex, replacement);
return this;
}
}

9
samples/Calc/Models/Operator.cs

@ -0,0 +1,9 @@
namespace Calc.Models;
public enum Operator
{
Add,
Subtract,
Multiply,
Divide
}

20
samples/Calc/Models/OperatorChar.cs

@ -0,0 +1,20 @@
using System.Linq;
namespace Calc.Models;
public static class OperatorChar
{
public const char Add = '+';
public const char Subtract = '-';
public const char Multiply = '*';
public const char Divide = '/';
public static readonly char[] Operators = { Add, Subtract, Multiply, Divide };
public static readonly char[] PrecedentOperators = { Multiply, Divide };
public static readonly char[] NonPrecedentOperators = { Add, Subtract };
public static bool IsAnOperator(char character)
{
return Operators.Contains(character);
}
}

28
samples/Calc/ViewLocator.cs

@ -0,0 +1,28 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Calc.ViewModels;
namespace Calc
{
public class ViewLocator : IDataTemplate
{
public IControl Build(object data)
{
var name = data.GetType().FullName!.Replace("ViewModel", "View");
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object data)
{
return data is ViewModelBase;
}
}
}

207
samples/Calc/ViewModels/MainWindowViewModel.cs

@ -0,0 +1,207 @@
using System;
using System.Globalization;
using System.IO;
using System.Reactive;
using Calc.Models;
using ReactiveUI;
namespace Calc.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private string _shownString = string.Empty;
private string _shownResult = string.Empty;
private int _numberOfOpeningParentheses;
private int _numberOfClosingParentheses;
// Commands
public ReactiveCommand<Unit, Unit> AddDecimalSeparatorCommand { get; }
public ReactiveCommand<int, Unit> AddNumberCommand { get; }
public ReactiveCommand<Operator, Unit> AddOperatorCommand { get; }
public ReactiveCommand<Unit, Unit> AddParenthesisCommand { get; }
public ReactiveCommand<Unit, Unit> AlternateNegativePositiveCommand { get; }
public ReactiveCommand<Unit, Unit> ClearScreenCommand { get; }
public ReactiveCommand<Unit, Unit> DeleteLastCommand { get; }
public ReactiveCommand<Unit, Unit> PickResultCommand { get; }
public MainWindowViewModel()
{
AddDecimalSeparatorCommand = ReactiveCommand.Create(AddDecimalSeparator);
AddNumberCommand = ReactiveCommand.Create<int>(AddNumber);
AddOperatorCommand = ReactiveCommand.Create<Operator>(AddOperator);
AddParenthesisCommand = ReactiveCommand.Create(AddParenthesis);
AlternateNegativePositiveCommand = ReactiveCommand.Create(AlternateNegativePositive);
ClearScreenCommand = ReactiveCommand.Create(ClearScreen);
DeleteLastCommand = ReactiveCommand.Create(DeleteLast);
PickResultCommand = ReactiveCommand.Create(PickResult);
}
public string ShownString
{
get => _shownString;
set => this.RaiseAndSetIfChanged(ref _shownString, value);
}
public string ShownResult
{
get => _shownResult;
set => this.RaiseAndSetIfChanged(ref _shownResult, value);
}
private void AddDecimalSeparator()
{
if (CanDecimalSeparatorBePlaced())
ShownString += CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
}
private void AddNumber(int value)
{
ShownString += value;
Calculate(ShownString);
}
private void AddOperator(Operator @operator)
{
if (ShownString[^1].Equals('('))
return;
if (IsLastInputAnOperator())
ShownString = ShownString[..^1];
ShownString += @operator switch
{
Operator.Add => OperatorChar.Add,
Operator.Subtract => OperatorChar.Subtract,
Operator.Multiply => OperatorChar.Multiply,
Operator.Divide => OperatorChar.Divide,
_ => throw new InvalidDataException("Operator not allowed")
};
}
private void AddParenthesis()
{
if (ShownString.Length == 0 || IsLastInputAnOperator() || ShownString[^1].Equals('('))
{
ShownString += "(";
_numberOfOpeningParentheses++;
}
else if (_numberOfClosingParentheses < _numberOfOpeningParentheses)
{
ShownString += ")";
_numberOfClosingParentheses++;
Calculate(ShownString);
}
}
private void AlternateNegativePositive()
{
var indexWhereSetOrUnsetSign = SetIndexWhereToSetOrUnsetSign();
if (ShownString.Length == 0 || ShownString[^1].Equals('('))
ShownString += OperatorChar.Subtract;
else
{
switch (ShownString[indexWhereSetOrUnsetSign])
{
case OperatorChar.Subtract:
if (indexWhereSetOrUnsetSign == 0 ||
ShownString[indexWhereSetOrUnsetSign - 1].Equals('(') ||
OperatorChar.IsAnOperator(ShownString[indexWhereSetOrUnsetSign - 1]))
ShownString = ShownString.Remove(indexWhereSetOrUnsetSign, 1);
else
// Add -
ShownString = ShownString[..indexWhereSetOrUnsetSign] +
OperatorChar.Subtract +
ShownString[indexWhereSetOrUnsetSign..];
break;
default:
// Add -
ShownString = ShownString[..indexWhereSetOrUnsetSign] +
OperatorChar.Subtract +
ShownString[indexWhereSetOrUnsetSign..];
break;
}
Calculate(ShownString);
}
}
private void Calculate(string calc)
{
ShownResult = Calculator.Calculate(calc);
}
private bool CanDecimalSeparatorBePlaced()
{
var indexLastDecimalSeparator = ShownString.LastIndexOf(
CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator,
StringComparison.Ordinal);
var indexLastOperator = ShownString.LastIndexOfAny(OperatorChar.Operators);
if (indexLastDecimalSeparator == -1 && indexLastOperator == -1)
return true;
return indexLastOperator > indexLastDecimalSeparator;
}
private void ClearScreen()
{
ShownString = string.Empty;
ShownResult = string.Empty;
_numberOfOpeningParentheses = 0;
_numberOfClosingParentheses = 0;
}
private void DeleteLast()
{
if (ShownString.Length == 1)
{
ClearScreen();
return;
}
// Update number of parentheses
switch (ShownString[^1])
{
case '(':
_numberOfOpeningParentheses--;
break;
case ')':
_numberOfClosingParentheses--;
break;
}
ShownString = ShownString[..^1];
Calculate(IsLastInputAnOperator() ? ShownString[..^1] : ShownString);
}
private bool IsLastInputAnOperator()
{
return OperatorChar.IsAnOperator(ShownString[^1]);
}
private static int MaxOf(int number1, int number2)
{
return number1 > number2 ? number1 : number2;
}
private void PickResult()
{
ShownString = ShownResult;
ShownResult = string.Empty;
}
private int SetIndexWhereToSetOrUnsetSign()
{
char[] nonSubstractOperators = { OperatorChar.Add, OperatorChar.Multiply, OperatorChar.Divide };
var indexAfterLastNonSubstractOperator = ShownString.LastIndexOfAny(nonSubstractOperators) + 1;
var indexOfLastSubstractOperator = ShownString.LastIndexOf(OperatorChar.Subtract);
var indexAfterLastParenthesis = ShownString.LastIndexOf('(') + 1;
var indexLastOperator = MaxOf(indexAfterLastNonSubstractOperator, indexOfLastSubstractOperator);
return MaxOf(indexAfterLastParenthesis, indexLastOperator);
}
}
}

8
samples/Calc/ViewModels/ViewModelBase.cs

@ -0,0 +1,8 @@
using ReactiveUI;
namespace Calc.ViewModels
{
public class ViewModelBase : ReactiveObject
{
}
}

377
samples/Calc/Views/MainView.axaml

@ -0,0 +1,377 @@
<UserControl xmlns="https://github.com/avaloniaui"
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:material="using:Material.Icons.Avalonia"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:viewModels="clr-namespace:Calc.ViewModels"
MaxWidth="800" MaxHeight="500" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
xmlns:m="using:Calc.Models"
mc:Ignorable="d"
x:Class="Calc.Views.MainView"
x:DataType="viewModels:MainWindowViewModel"
x:CompileBindings="False">
<UserControl.Styles>
<Style Selector="Button">
<Setter Property="Margin" Value="5" />
</Style>
<Style Selector="Button TextBlock">
<Setter Property="FontSize" Value="20" />
</Style>
<Style Selector="TextBlock.screen">
<Setter Property="Background" Value="#2f2a2c" />
<Setter Property="Margin" Value="5" />
<Setter Property="FontSize" Value="30" />
<Setter Property="MinHeight" Value="35" />
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="Foreground" Value="#ddffffff" />
</Style>
</UserControl.Styles>
<UserControl.KeyBindings>
<!-- 0 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D0">
<KeyBinding.CommandParameter>
<system:Int32>0</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad0">
<KeyBinding.CommandParameter>
<system:Int32>0</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 1 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D1">
<KeyBinding.CommandParameter>
<system:Int32>1</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad1">
<KeyBinding.CommandParameter>
<system:Int32>1</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 2 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D2">
<KeyBinding.CommandParameter>
<system:Int32>2</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad2">
<KeyBinding.CommandParameter>
<system:Int32>2</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 3 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D3">
<KeyBinding.CommandParameter>
<system:Int32>3</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad3">
<KeyBinding.CommandParameter>
<system:Int32>3</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 4 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D4">
<KeyBinding.CommandParameter>
<system:Int32>4</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad4">
<KeyBinding.CommandParameter>
<system:Int32>4</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 5 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D5">
<KeyBinding.CommandParameter>
<system:Int32>5</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad5">
<KeyBinding.CommandParameter>
<system:Int32>5</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 6 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D6">
<KeyBinding.CommandParameter>
<system:Int32>6</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad6">
<KeyBinding.CommandParameter>
<system:Int32>6</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 7 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D7">
<KeyBinding.CommandParameter>
<system:Int32>7</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad7">
<KeyBinding.CommandParameter>
<system:Int32>7</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 8 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D8">
<KeyBinding.CommandParameter>
<system:Int32>8</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad8">
<KeyBinding.CommandParameter>
<system:Int32>8</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- 9 -->
<KeyBinding Command="{Binding AddNumber}" Gesture="D9">
<KeyBinding.CommandParameter>
<system:Int32>9</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddNumber}" Gesture="NumPad9">
<KeyBinding.CommandParameter>
<system:Int32>9</system:Int32>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- + -->
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="Add">
<KeyBinding.CommandParameter>
<m:Operator>Add</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="OemPlus">
<KeyBinding.CommandParameter>
<m:Operator>Add</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- - -->
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="Subtract">
<KeyBinding.CommandParameter>
<m:Operator>Subtract</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="OemMinus">
<KeyBinding.CommandParameter>
<m:Operator>Subtract</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- . -->
<KeyBinding Command="{Binding AddDecimalSeparatorCommand}" Gesture="OemPeriod" />
<!-- +- -->
<KeyBinding Command="{Binding AlternateNegativePositiveCommand}" Gesture="Alt+Subtract" />
<KeyBinding Command="{Binding AlternateNegativePositiveCommand}" Gesture="Alt+OemMinus" />
<!-- Backspace -->
<KeyBinding Command="{Binding DeleteLastCommand}" Gesture="Back" />
<!-- Delete -->
<KeyBinding Command="{Binding ClearScreenCommand}" Gesture="Escape" />
<KeyBinding Command="{Binding ClearScreenCommand}" Gesture="Delete" />
<!-- * -->
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="Multiply">
<KeyBinding.CommandParameter>
<m:Operator>Multiply</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- / -->
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="Divide">
<KeyBinding.CommandParameter>
<m:Operator>Divide</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<KeyBinding Command="{Binding AddOperatorCommand}" Gesture="Oem2">
<KeyBinding.CommandParameter>
<m:Operator>Divide</m:Operator>
</KeyBinding.CommandParameter>
</KeyBinding>
<!-- () -->
<KeyBinding Command="{Binding AddParenthesisCommand}" Gesture="OemOpenBrackets" />
<KeyBinding Command="{Binding AddParenthesisCommand}" Gesture="OemCloseBrackets" />
<!-- = -->
<KeyBinding Command="{Binding PickResultCommand}" Gesture="Enter" />
</UserControl.KeyBindings>
<Grid Margin="5" RowDefinitions="Auto, Auto, *">
<!-- Screens -->
<TextBlock
Classes="screen"
Grid.Row="0"
Text="{Binding ShownString}" />
<TextBlock
Classes="screen"
Grid.Row="1"
Text="{Binding ShownResult}" />
<!-- Keys -->
<Grid
ColumnDefinitions="*,*,*,*,*"
Grid.Row="2"
RowDefinitions="*,*,*,*">
<!-- Numeric keys -->
<Button
Command="{Binding AddNumber}"
Grid.Column="0"
Grid.Row="3">
<Button.CommandParameter>
<system:Int32>0</system:Int32>
</Button.CommandParameter>
0
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="0"
Grid.Row="2">
<Button.CommandParameter>
<system:Int32>1</system:Int32>
</Button.CommandParameter>
1
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="1"
Grid.Row="2">
<Button.CommandParameter>
<system:Int32>2</system:Int32>
</Button.CommandParameter>
2
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="2"
Grid.Row="2">
<Button.CommandParameter>
<system:Int32>3</system:Int32>
</Button.CommandParameter>
3
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="0"
Grid.Row="1">
<Button.CommandParameter>
<system:Int32>4</system:Int32>
</Button.CommandParameter>
4
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="1"
Grid.Row="1">
<Button.CommandParameter>
<system:Int32>5</system:Int32>
</Button.CommandParameter>
5
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="2"
Grid.Row="1">
<Button.CommandParameter>
<system:Int32>6</system:Int32>
</Button.CommandParameter>
6
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="0"
Grid.Row="0">
<Button.CommandParameter>
<system:Int32>7</system:Int32>
</Button.CommandParameter>
7
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="1"
Grid.Row="0">
<Button.CommandParameter>
<system:Int32>8</system:Int32>
</Button.CommandParameter>
8
</Button>
<Button
Command="{Binding AddNumber}"
Grid.Column="2"
Grid.Row="0">
<Button.CommandParameter>
<system:Int32>9</system:Int32>
</Button.CommandParameter>
9
</Button>
<!-- Non-numeric keys -->
<Button
Command="{Binding AddDecimalSeparator}"
Grid.Column="1"
Grid.Row="3">
.
</Button>
<Button
Command="{Binding AlternateNegativePositive}"
Grid.Column="2"
Grid.Row="3">
+/-
</Button>
<Button
Command="{Binding DeleteLast}"
Grid.Column="3"
Grid.Row="0">
<material:MaterialIcon Kind="Backspace" />
</Button>
<Button
Command="{Binding ClearScreen}"
Grid.Column="4"
Grid.Row="0">
<material:MaterialIcon Kind="DeleteForever" />
</Button>
<Button
Command="{Binding AddOperator}"
Grid.Column="3"
Grid.Row="1">
<Button.CommandParameter>
<m:Operator>Multiply</m:Operator>
</Button.CommandParameter>
<material:MaterialIcon Kind="Multiply" />
</Button>
<Button
Command="{Binding AddOperator}"
Grid.Column="4"
Grid.Row="1">
<Button.CommandParameter>
<m:Operator>Divide</m:Operator>
</Button.CommandParameter>
<material:MaterialIcon Kind="Division" />
</Button>
<Button
Command="{Binding AddOperator}"
Grid.Column="3"
Grid.Row="2">
<Button.CommandParameter>
<m:Operator>Add</m:Operator>
</Button.CommandParameter>
<material:MaterialIcon Kind="Add" />
</Button>
<Button
Command="{Binding AddOperator}"
Grid.Column="4"
Grid.Row="2">
<Button.CommandParameter>
<m:Operator>Subtract</m:Operator>
</Button.CommandParameter>
<material:MaterialIcon Kind="Minus" />
</Button>
<Button
Command="{Binding AddParenthesis}"
Grid.Column="3"
Grid.Row="3">
<material:MaterialIcon Kind="CodeParentheses" />
</Button>
<Button
Command="{Binding PickResult}"
Grid.Column="4"
Grid.Row="3">
<material:MaterialIcon Kind="Equal" />
</Button>
</Grid>
</Grid>
</UserControl>

25
samples/Calc/Views/MainView.axaml.cs

@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Calc.Views;
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
protected override void OnLoaded()
{
base.OnLoaded();
Focus();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

16
samples/Calc/Views/MainWindow.axaml

@ -0,0 +1,16 @@
<Window
Height="500"
Icon="/Assets/avalonia-logo.ico"
Title="Calc"
Width="600"
d:DesignHeight="450"
d:DesignWidth="600"
mc:Ignorable="d"
x:Class="Calc.Views.MainWindow"
xmlns="https://github.com/avaloniaui"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:Calc.Views" Focusable="False">
<views:MainView Focusable="True" />
</Window>

12
samples/Calc/Views/MainWindow.axaml.cs

@ -0,0 +1,12 @@
using Avalonia.Controls;
namespace Calc.Views
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

3
samples/ControlCatalog.Blazor.Web/App.razor.cs

@ -2,12 +2,13 @@ using Avalonia;
using Avalonia.Web.Blazor;
namespace ControlCatalog.Blazor.Web;
using Calc;
public partial class App
{
protected override void OnParametersSet()
{
AppBuilder.Configure<ControlCatalog.App>()
AppBuilder.Configure<Calc.App>()
.UseBlazor()
// .With(new SkiaOptions { CustomGpuFactory = null }) // uncomment to disable GPU/GL rendering
.SetupWithSingleViewLifetime();

4
samples/ControlCatalog.Blazor.Web/ControlCatalog.Blazor.Web.csproj

@ -16,7 +16,9 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
<ProjectReference Include="..\..\src\Web\Avalonia.Web.Blazor\Avalonia.Web.Blazor.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\Calc\Calc.csproj" />
<PackageReference Include="Material.Avalonia" Version="3.0.0-avalonia11-preview2" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.2.0" />
</ItemGroup>
<Import Project="..\..\build\ReferenceCoreLibraries.props" />

2
src/Avalonia.Controls/Button.cs

@ -347,6 +347,8 @@ namespace Avalonia.Controls
if (!e.Handled && Command?.CanExecute(CommandParameter) == true)
{
Console.WriteLine("Executing");
Console.WriteLine(Command.GetType().ToString());
Command.Execute(CommandParameter);
e.Handled = true;
}

Loading…
Cancel
Save