UWP计算器开发:非法表达式异常处理与温标双向转换实现咨询
Hey there! Let's get your UWP calculator sorted out—both the exception handling for wonky expressions and the temperature conversion. I'll break this down step by step with code changes you can drop right in.
The DataTable.Compute method throws several types of exceptions when faced with invalid syntax, division by zero, or other issues. Right now your catch block is empty, so we'll expand it to catch those cases, show "Failed" to the user, then reset the calculator. We'll also add a check for overly long input to prevent crashes there too.
First, let's create a reusable reset method to avoid repeating code:
private void ResetCalculator() { textBox.Text = string.Empty; }
Now update your equal button click handler to handle exceptions and input length:
private void Button_ClickEqual(object sender, RoutedEventArgs e) { // Check for overly long input first if (textBox.Text.Length > 20) // Adjust this number based on your needs { textBox.Text = "Failed"; // Auto-reset after a short delay (optional but user-friendly) var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); return; } try { object q = new DataTable().Compute(textBox.Text, null); textBox.Text = q.ToString(); } catch (SyntaxErrorException) // Thrown for invalid expressions like "5+-*/6" catch (DivideByZeroException) // Thrown when dividing by zero catch (Exception) // Catch-all for any other unexpected issues { textBox.Text = "Failed"; // Auto-reset after a short delay var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); } }
Note: The auto-reset timer is optional but makes the user experience smoother—after showing "Failed", it clears the input automatically after 1.5 seconds. You can remove that part if you prefer the user to click Reset manually.
For the temperature buttons, we'll parse the current value in the text box, perform the conversion, and display the result. If the input isn't a valid number, we'll show "Failed" too.
Update your two temperature button handlers:
private void Button_Click_fc_(object sender, RoutedEventArgs e) { // Convert Fahrenheit to Celsius: C = (F - 32) * 5/9 if (double.TryParse(textBox.Text, out double fahrenheit)) { double celsius = Math.Round((fahrenheit - 32) * 5 / 9, 2); // Round to 2 decimals for readability textBox.Text = $"{celsius} °C"; } else { textBox.Text = "Failed"; var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); } } private void Button_Click_cf_(object sender, RoutedEventArgs e) { // Convert Celsius to Fahrenheit: F = (C * 9/5) + 32 if (double.TryParse(textBox.Text, out double celsius)) { double fahrenheit = Math.Round((celsius * 9 / 5) + 32, 2); textBox.Text = $"{fahrenheit} °F"; } else { textBox.Text = "Failed"; var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); } }
We use double.TryParse to safely check if the input is a valid number—no exceptions thrown here, just a clean check. Rounding to 2 decimal places makes the result look nicer, but you can adjust that or remove it if you want more precision.
Here's the complete MainPage class with all the changes:
using System; using System.Data; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace Calc { public sealed partial class MainPage : Page { public static bool fClick = false; string input = string.Empty; string x = string.Empty; string y = string.Empty; char operation; double result = 0.0; public MainPage() { this.InitializeComponent(); } // Reusable reset method private void ResetCalculator() { textBox.Text = string.Empty; } // Number button handlers (unchanged) private void Button_Click(object sender, RoutedEventArgs e) { textBox.Text += '1'; } private void Button_Click_1(object sender, RoutedEventArgs e) { textBox.Text += '2'; } private void Button_Click_2(object sender, RoutedEventArgs e) { textBox.Text += '3'; } private void Button_Click_3(object sender, RoutedEventArgs e) { textBox.Text += '4'; } private void Button_Click_4(object sender, RoutedEventArgs e) { textBox.Text += '5'; } private void Button_Click_5(object sender, RoutedEventArgs e) { textBox.Text += '6'; } private void Button_Click_6(object sender, RoutedEventArgs e) { textBox.Text += '7'; } private void Button_Click_7(object sender, RoutedEventArgs e) { textBox.Text += '8'; } private void Button_Click_8(object sender, RoutedEventArgs e) { textBox.Text += '9'; } private void Button_Click_9(object sender, RoutedEventArgs e) { textBox.Text += "42"; } private void Button_Click_10(object sender, RoutedEventArgs e) { textBox.Text += '0'; } // Operator button handlers (unchanged) private void Button_Click_11(object sender, RoutedEventArgs e) { textBox.Text += '*'; } private void Button_ClickPlus(object sender, RoutedEventArgs e) { textBox.Text += '+'; } private void Button_ClickMinus(object sender, RoutedEventArgs e) { textBox.Text += '-'; } private void Button_ClickTimes(object sender, RoutedEventArgs e) { textBox.Text += '*'; } private void Button_ClickDEv(object sender, RoutedEventArgs e) { textBox.Text += '/'; } // Updated equal button with exception handling private void Button_ClickEqual(object sender, RoutedEventArgs e) { if (textBox.Text.Length > 20) { textBox.Text = "Failed"; var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); return; } try { object q = new DataTable().Compute(textBox.Text, null); textBox.Text = q.ToString(); } catch (SyntaxErrorException) catch (DivideByZeroException) catch (Exception) { textBox.Text = "Failed"; var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); } } private void Button_ClickReset(object sender, RoutedEventArgs e) { ResetCalculator(); } // Updated Fahrenheit to Celsius conversion private void Button_Click_fc_(object sender, RoutedEventArgs e) { if (double.TryParse(textBox.Text, out double fahrenheit)) { double celsius = Math.Round((fahrenheit - 32) * 5 / 9, 2); textBox.Text = $"{celsius} °C"; } else { textBox.Text = "Failed"; var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); } } // Updated Celsius to Fahrenheit conversion private void Button_Click_cf_(object sender, RoutedEventArgs e) { if (double.TryParse(textBox.Text, out double celsius)) { double fahrenheit = Math.Round((celsius * 9 / 5) + 32, 2); textBox.Text = $"{fahrenheit} °F"; } else { textBox.Text = "Failed"; var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1.5) }; timer.Tick += (s, args) => { ResetCalculator(); timer.Stop(); }; timer.Start(); } } } }
Your XAML code doesn't need any changes—those buttons are already set up correctly.
This should handle all your cases:
- Invalid expressions like "5+-*/6" will show "Failed" then reset
- Overly long inputs will trigger the same "Failed" state
- Valid expressions (including "5--6") will still calculate correctly
- Temperature conversion works when a valid number is entered, and shows "Failed" if not
内容的提问来源于stack exchange,提问作者user14528458

