同样用两种方式实现动画,各位自行选择。实现了一个ArithmeticConverter类。
ArithmeticConverter.cs类
using Avalonia.Data.Converters; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks;namespace Shares.Avalonia {public class ArithmeticConverter : IValueConverter{public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture){if (value == null) return 0.0;if (!double.TryParse(value.ToString(), out double input)) return value;if (parameter == null) return input;string[] ops = parameter.ToString()!.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);foreach (var op in ops){input = ApplyOperation(input, op.Trim());}return input;}public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture){if (value == null) return 0.0;if (!double.TryParse(value.ToString(), out double input)) return value;if (parameter == null) return input;string[] ops = parameter.ToString()!.Split(new[] { ',', ';',':'}, StringSplitOptions.RemoveEmptyEntries);// 倒序执行逆运算for (int i = ops.Length - 1; i >= 0; i--){input = ApplyOperationBack(input, ops[i].Trim());}return input;}private double ApplyOperation(double input, string op){try{if (op.StartsWith("+")) return input + double.Parse(op[1..]);if (op.StartsWith("-")) return input - double.Parse(op[1..]);if (op.StartsWith("*")) return input * double.Parse(op[1..]);if (op.StartsWith("/")) return double.Parse(op[1..]) != 0 ? input / double.Parse(op[1..]) : 0;if (op.StartsWith("^")){double power = double.Parse(op[1..]);// 负数的非整数幂检查if (input < 0 && power % 1 != 0){Console.WriteLine($"警告:负数底数 {input} 与非整数指数 {power} 会产生 NaN");return double.NaN;}return Math.Pow(input, power);}if (op == "√") return input >= 0 ? Math.Sqrt(input) : double.NaN;if (op == "abs") return Math.Abs(input);if (op == "neg") return -input;if (op == "floor") return Math.Floor(input);if (op == "ceil") return Math.Ceiling(input);if (op == "round") return Math.Round(input);// 三角函数(度数模式)if (op == "sin") return Math.Sin(input * Math.PI / 180);if (op == "cos") return Math.Cos(input * Math.PI / 180);if (op == "tan"){double angleMod = input % 180;if (Math.Abs(angleMod - 90) < 1e-10){Console.WriteLine($"警告:tan({input}) 接近 90 + k*180 度奇点");return double.NaN;}return Math.Tan(input * Math.PI / 180);}if (op == "asin"){if (input < -1 || input > 1){Console.WriteLine($"警告:asin({input}) 超出定义域 [-1,1]");return double.NaN;}return Math.Asin(input) * 180 / Math.PI;}if (op == "acos"){if (input < -1 || input > 1){Console.WriteLine($"警告:acos({input}) 超出定义域 [-1,1]");return double.NaN;}return Math.Acos(input) * 180 / Math.PI;}if (op == "atan") return Math.Atan(input) * 180 / Math.PI;// 对数与指数if (op == "ln") return input > 0 ? Math.Log(input) : double.NaN;if (op.StartsWith("log")){double baseVal = 10;if (op.Length > 3) double.TryParse(op[3..], out baseVal);return input > 0 ? Math.Log(input, baseVal) : double.NaN;}if (op == "exp") return Math.Exp(input);}catch (Exception ex){Console.WriteLine($"警告:ApplyOperation错误信息为{ex.Message}");}return input;}private double ApplyOperationBack(double input, string op){try{if (op.StartsWith("+")) return input - double.Parse(op[1..]);if (op.StartsWith("-")) return input + double.Parse(op[1..]);if (op.StartsWith("*")){double factor = double.Parse(op[1..]);if (factor != 0) return input / factor;}if (op.StartsWith("/")){double factor = double.Parse(op[1..]);return input * factor;}if (op.StartsWith("^")){double power = double.Parse(op[1..]);if (input < 0 && power % 1 != 0){Console.WriteLine($"警告:负数底数 {input} 与非整数指数 {power} 会产生 NaN");return double.NaN;}if (power != 0) return Math.Pow(input, 1 / power);}if (op == "√") return input * input;if (op == "neg") return -input;if (op == "abs" || op == "floor" || op == "ceil" || op == "round"){Console.WriteLine($"警告:操作 '{op}' 不可逆,返回当前值");return input;}// 三角函数逆运算(度数模式)if (op == "sin") return Math.Asin(input) * 180 / Math.PI;if (op == "cos") return Math.Acos(input) * 180 / Math.PI;if (op == "tan"){double angleRad = Math.Atan(input);double angleDeg = angleRad * 180 / Math.PI;return angleDeg;}if (op == "asin") return Math.Sin(input * Math.PI / 180);if (op == "acos") return Math.Cos(input * Math.PI / 180);if (op == "atan") return Math.Tan(input * Math.PI / 180);// 对数与指数逆运算if (op == "ln") return Math.Exp(input);if (op.StartsWith("log")){double baseVal = 10;if (op.Length > 3) double.TryParse(op[3..], out baseVal);return Math.Pow(baseVal, input);}if (op == "exp") return Math.Log(input);}catch (Exception ex){Console.WriteLine($"警告:ApplyOperationBack错误信息为{ex.Message}");}return input;}} }
XamlAnimation.axaml代码
<Window 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"Height="300" Width="300"x:Class="AvaloniaUI.XamlAnimation"Title="XamlAnimation" Name="window"><Window.Resources><ArithmeticConverter x:Key="converter"/></Window.Resources><Window.Styles><Style Selector="Button.Animation1"><Setter Property="Height" Value="40"/><Setter Property="Width" Value="160"/><Style Selector="^:pointerover"><Style.Animations><Animation Duration="0:0:5" FillMode="None"><KeyFrame Cue="100%"><Setter Property="Width" Value="{Binding #window.Width, Converter={StaticResource converter}, ConverterParameter=-100}"/><Setter Property="Height" Value="{Binding #window.Height, Converter={StaticResource converter}, ConverterParameter=-100;/3}"/></KeyFrame></Animation></Style.Animations></Style></Style><Style Selector="Button.Animation2"><Setter Property="Height" Value="40"/><Setter Property="Width" Value="160"/><Setter Property="Transitions"><Transitions><DoubleTransition Property="Width" Duration="0:0:5"/><DoubleTransition Property="Height" Duration="0:0:5"/></Transitions></Setter><Style Selector="^:pointerover"><Setter Property="Width" Value="{Binding #window.Width, Converter={StaticResource converter}, ConverterParameter=-100}"/><Setter Property="Height" Value="{Binding #window.Height, Converter={StaticResource converter}, ConverterParameter=-100;/3}"/></Style></Style></Window.Styles><Button Padding="10" Classes="Animation2"HorizontalAlignment="Center" VerticalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"Content="Pointer over and Make Me Grow"></Button> </Window>
XamlAnimation.axaml.cs代码
using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml;namespace AvaloniaUI;public partial class XamlAnimation : Window {public XamlAnimation(){InitializeComponent();} }
运行效果