[Silverlight C#]反向波兰语表示法计算器教程

你们有没有曾经使用过

反向波兰语符号计算器? 我上高中时 它很容易成为有史以来最好的计算器(HP = 32SII)。 RPN很棒,因为您不必使用括号。 堆栈和键入操作员的顺序保持操作顺序。

今天,我将指导您创建一个。 请注意,本教程从技术上讲是针对Silverlight的,但是除标记的部分外,它可以批量应用于WinForms或WPF。 大多数情况是简单的堆栈逻辑,并且存在于所有.NET平台上。

注意:我假设您熟悉堆栈操作。 如果没有,请访问链接的MSDN页面以获取信息。

在开始编程之前,您必须了解后缀表示法。 考虑以下:

5 6 +
这是一个后缀表达式,等于11。对其进行评估的逻辑步骤是:
  • 手推(5)
  • 手推(6)
  • var b = Pop()
  • var a = Pop()
  • 推(a + b)
  • 窥视()

考虑一个更复杂的表达式:

10 4 6 + 9 * -
该值为-80。 它与Infix(标准)表示法中的10-((4 + 6)* 9)等价。 此处遵循相同的基本步骤。
  • 手推(10)
  • 手推(4)
  • 手推(6)
  • var b = Pop()
  • var a = Pop()
  • 推(a + b)
  • 手推(9)
  • var b = Pop()
  • var a = Pop()
  • 推(a * b)
  • var b = Pop()
  • var a = Pop()
  • 推(a-b)
  • 窥视()

基本逻辑是将数字压入堆栈,直到遇到运算符为止。 此时,您将顶部的两个从堆栈中弹出,并使用运算符对其进行评估,然后将结果推回堆栈中。 经过评估,请看一下显示。

用RPN计算器术语来说,有一个ENTER按钮将一个值压入堆栈。 另外,为节省时间,如果您当前正在输入数字,则按操作员按钮也将数字推入堆栈。

因此对于

5 6 + 3 * ,我们将推送:

5 [ENTER] 6 [+] 3 [*]。

对于

1 6 2 / 3 4 / * + (相当于1 + (( 6 / 2 ) * ( 3 / 4 )) ,您可以按下:

1 [ENTER] 6 [ENTER] 2 [/] 3 [ENTER] 4 [/] [*] [+]

在标准计算器上,您必须使用“记忆”功能以正确的操作顺序执行此操作。 使用图形计算器,您必须使用括号。 但是,由于您可以将状态保留在堆栈中,因此您不必担心RPN calc中的任何状态。

因此,事不宜迟,让我们进入代码。

设定

我们显然需要一个堆栈:

private Stack<double> stack;
我们还需要一些词典来将键盘键与字符串相关联,因为我们不信任用户自己输入数字:

private Dictionary<Key, string> opKeys = new Dictionary<Key, string>();
private Dictionary<Key, string> numKeys = new Dictionary<Key, string>(); 
private void InitializeDictionaries()
{
    opKeys.Add(Key.C, "C");
    opKeys.Add(Key.Back, "B");
    opKeys.Add(Key.Add, "+");
    opKeys.Add(Key.Subtract, "-");
    opKeys.Add(Key.Multiply, "*");
    opKeys.Add(Key.Divide, "/");
    opKeys.Add(Key.Enter, "E");
    opKeys.Add(Key.Decimal, "."); 
    numKeys.Add(Key.D0, "0");
    numKeys.Add(Key.D1, "1");
    numKeys.Add(Key.D2, "2");
    numKeys.Add(Key.D3, "3");
    numKeys.Add(Key.D4, "4");
    numKeys.Add(Key.D5, "5");
    numKeys.Add(Key.D6, "6");
    numKeys.Add(Key.D7, "7");
    numKeys.Add(Key.D8, "8");
    numKeys.Add(Key.D9, "9");
    numKeys.Add(Key.NumPad0,  "0");
    numKeys.Add(Key.NumPad1,  "1");
    numKeys.Add(Key.NumPad2,  "2");
    numKeys.Add(Key.NumPad3,  "3");
    numKeys.Add(Key.NumPad4,  "4");
    numKeys.Add(Key.NumPad5,  "5");
    numKeys.Add(Key.NumPad6,  "6");
    numKeys.Add(Key.NumPad7,  "7");
    numKeys.Add(Key.NumPad8,  "8");
    numKeys.Add(Key.NumPad9,  "9");
}
现在,我们将对运算符使用Lambda方法。 这使事情变得很简单。 如果您不熟悉这里发生的事情,欢迎阅读有关Lambda教程 。 从根本上讲,它们是编写匿名方法的简便方法。 Func对象是将这些方法存储为对象的一种方法。 我们将创建一个以字符串为键的Funcs字典:

private Dictionary<string, Func<double, double, double>> op =
    new Dictionary<string, Func<double, double, double>>(); 
private void InitializeOp()
{
    op.Add("+", (a, B) => a + B);
    op.Add("-", (a, B) => a - B);
    op.Add("*", (a, B) => a * B);
    op.Add("/", (a, B) => a / B);
}
如果您觉得这很奇怪,下面是我们如何调用此示例。 这不在项目中。 这只是在字典中使用Funcs的示例。
double a = 5, b = 6;
double result = op["+"](5, 6);
现在,我们将方法存储在字典中,并根据传递的运算符,调用适当的运算符。 这非常有用,因为它使我们可以跳过开关或if语句。

另外,我们还需要跟踪两个状态:

private bool clearOnNext, errorState;
clearOnNext让我们知道按下的下一个数字是开始一个新数字还是追加到当前数字之后。 errorState是一个简单的布尔值,可以让我们知道我们当前是否正在向用户报告错误(例如Div By Zero或Out of Stack)。 Silverlight特定:XAML MARKUP (显示代码)

这是我们正在使用的XAML标记。 这可以由WinForms复制,但是我更愿意在可能的情况下使用Silverlight / WPF。

<Grid x:Name="LayoutRoot" Background="White"> 
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <!-- Max length: 15 -->
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="30" />
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="3">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Text="Stack Depth" Grid.Row="0" FontSize="8" TextWrapping="Wrap" VerticalAlignment="Bottom" HorizontalAlignment="Center" />
                    <TextBlock Text="0" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Center" x:Name="stackDepthTextBlock" />
                </Grid>
            </Border>
            <Border Grid.Column="1" BorderBrush="Black" BorderThickness="1" CornerRadius="3">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Button x:Name="copyButton" Content="Copy" Click="copyButton_Click" />
                    <Button x:Name="pasteButton" Content="Paste" Grid.Row="1" Click="pasteButton_Click" />
                </Grid>
            </Border>
            <TextBox IsReadOnly="True" x:Name="displayTextBox" Text="" 
             Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" HorizontalAlignment="Stretch" TextAlignment="Right" 
             FontFamily="Courier New" FontSize="26" FontWeight="ExtraBold" 
             KeyUp="DisplayTextBox_KeyUp" />
        </Grid>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions> 
            <!-- Buttons --> 
            <Button Content="Enter" Tag="E" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Click="Button_Click" IsTabStop="False" />
            <Button Content="C" Tag="C" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="?" Tag="B" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" /> 
            <Button Content="7" Tag="7" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="8" Tag="8" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="9" Tag="9" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="÷" Tag="/" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="1" Grid.Column="3" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" /> 
            <Button Content="4" Tag="7" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="1" Click="Button_Click" />
            <Button Content="5" Tag="8" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="1" Click="Button_Click" />
            <Button Content="6" Tag="9" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="1" Click="Button_Click" />
            <Button Content="×" Tag="*" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="3" Grid.ColumnSpan="1" Click="Button_Click" /> 
            <Button Content="4" Tag="4" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="5" Tag="5" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="6" Tag="6" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="×" Tag="*" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="2" Grid.Column="3" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" /> 
            <Button Content="1" Tag="1" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="2" Tag="2" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="3" Tag="3" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="-" Tag="-" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" /> 
            <Button Content="0" Tag="0" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Click="Button_Click" IsTabStop="False" />
            <Button Content="." Tag="." Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <Button Content="+" Tag="+" Style="{StaticResource ViewboxButton}" Margin="2" Grid.Row="4" Grid.Column="3" Grid.ColumnSpan="1" Click="Button_Click" IsTabStop="False" />
            <!-- /Buttons -->
        </Grid>
    </Grid>
</Grid>
我所做的一件整洁的事情是为Button创建了新样式。 我从MSDN复制了Button的默认模板,但是我做了一个小的更改,就是将<ContentPresenter>放在<Viewbox>内 。 Viewbox是一个简洁的控件,它将拉伸和缩放单个孩子以填充所有可用空间。 没有它,按钮可以缩放到适合的大小,但是里面的文本将保持相同的大小。 有了它,文本就会缩放以填充按钮。 这是模板。

<Style x:Key="ViewboxButton" TargetType="Button">
    <Setter Property="Background" Value="#FF1F3B53"/>
    <Setter Property="Foreground" Value="#FF000000"/>
    <Setter Property="Padding" Value="3"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="BorderBrush">
        <Setter.Value>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFA3AEB9" Offset="0"/>
                <GradientStop Color="#FF8399A9" Offset="0.375"/>
                <GradientStop Color="#FF718597" Offset="0.375"/>
                <GradientStop Color="#FF617584" Offset="1"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid>
                    <vsm:VisualStateManager.VisualStateGroups>
                        <vsm:VisualStateGroup x:Name="CommonStates">
                            <vsm:VisualState x:Name="Normal"/>
                            <vsm:VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity" To="1"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#F2FFFFFF"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#CCFFFFFF"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#7FFFFFFF"/>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="#FF6DBDD1"/>
                                    <DoubleAnimation Duration="0" Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity" To="1"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" To="#D8FFFFFF"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" To="#C6FFFFFF"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" To="#8CFFFFFF"/>
                                    <ColorAnimation Duration="0" Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" To="#3FFFFFFF"/>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="Disabled">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To=".55"/>
                                </Storyboard>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                        <vsm:VisualStateGroup x:Name="FocusStates">
                            <vsm:VisualState x:Name="Focused">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1"/>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="Unfocused" />
                        </vsm:VisualStateGroup>
                    </vsm:VisualStateManager.VisualStateGroups>
                    <Border x:Name="Background" CornerRadius="3" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
                        <Grid Background="{TemplateBinding Background}"  Margin="1">
                            <Border Opacity="0"  x:Name="BackgroundAnimation" Background="#FF448DCA" />
                            <Rectangle x:Name="BackgroundGradient" >
                                <Rectangle.Fill>
                                    <LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
                                        <GradientStop Color="#FFFFFFFF" Offset="0" />
                                        <GradientStop Color="#F9FFFFFF" Offset="0.375" />
                                        <GradientStop Color="#E5FFFFFF" Offset="0.625" />
                                        <GradientStop Color="#C6FFFFFF" Offset="1" />
                                    </LinearGradientBrush>
                                </Rectangle.Fill>
                            </Rectangle>
                        </Grid>
                    </Border>
                    <Viewbox>
                        <ContentPresenter Content="{TemplateBinding Content}" />
                    </Viewbox>
                    <Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
                    <Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
非银光专用

如果您不是在Silverlight中进行此操作,则在本教程的其余部分中要注意的重要一点是,我假设您创建了一个名为“ displayTextBox”的只读文本框。 您可以随意命名,只需确保在代码中也进行更改即可。 我假设的另一件事是,您已经创建了所有按钮,并将其Tag属性设置为其数字或运算符值。 同样,他们都应为其Click事件调用相同的处理程序:“ Button_Click”。 还有一件事,我已将事件处理程序附加到displayTextBox的KeyUp事件。

为了方便起见,这是我们将要使用的属性:

private double current
{
    get
    {
        if (displayTextBox.Text == string.Empty)
            displayTextBox.Text = "0";
        return double.Parse(displayTextBox.Text);
    }
}
这只是将TextBox中的内容解析为一个double。 初始化

这是我们的构造函数的外观:


public MainPage()
{
    InitializeComponent();
    InitializeDictionaries();
    InitializeOp();
    stack = new Stack<double>();
    this.Loaded += (s, ea) =>
    {
        if (!App.Current.IsRunningOutOfBrowser)
            System.Windows.Browser.HtmlPage.Plugin.Focus();
        displayTextBox.Focus();
    };
    clearOnNext = false;
    errorState = false;
}
这里也有一个lambda。 只是在加载程序时将焦点设置到Display TextBox上的快速事件处理程序。 由于某些原因,Silverlight应用程序启动时不会自动对焦,因此我添加了一行内容,告诉浏览器首先将焦点放在SL应用程序上。 方法

我们需要添加的最简单的方法必须处理输入。 我们将从处理程序中调用此方法。


private void ProcessInput(string input)
{
    if (clearOnNext)
    {
        displayTextBox.Text = string.Empty;
        clearOnNext = false;
        errorState = false;
    }
    displayTextBox.Text += input;
}
它检查我们是否正在开始新的号码。 如果是这样,它将清除它并重置状态,否则,它将仅追加文本。

我们还需要一种方法来处理特殊字符(例如“清除”,“输入”,“退格”和“十进制”)以及运算符


private void ProcessSpecial(string input)
{
    switch (input)
    {
        case "C":
            if (displayTextBox.Text.Length > 0)
                displayTextBox.Text = string.Empty;
            else
            {
                stack.Clear();
                RefreshDepthText();
            }
            clearOnNext = false;
            break;
        case "B":
            if (!clearOnNext && displayTextBox.Text.Length > 0)
                displayTextBox.Text = displayTextBox.Text.Substring(0, displayTextBox.Text.Length - 1);
            break;
        case ".":
            if (!displayTextBox.Text.Contains("."))
            {
                if (displayTextBox.Text.Length < 1 || errorState)
                    ProcessInput("0.");
                else
                    ProcessInput(".");
            }
            break;
        case "E":
            Enter();
            break;
        case "+":
        case "-":
        case "*":
        case "/":
            DoOp(input);
            break;
    }
}
这一步会在switch语句中演练各种可能性,并采取适当的措施。 此时,此处定义的某些方法尚未声明。 我们将尽快对此进行补救。 我还将解释每种情况。

情况“ C”很清楚。 第一次单击,将清除显示。 第二(如果显示已经很清晰,则为第一)清除堆栈。

情况“ B”为退格。 子串(如果有空间)。

案件 ”。” 处理小数。 我们只允许其中一个,为了视觉起见,如果单击的是第一个按钮,请在前面添加一个0。

输入情况“ E”。 我们将尽快编写该方法。

其余的情况是操作员。 我们还将很快讨论该方法。

计算器逻辑方法

现在是Enter方法:


private void Enter()
{
    if (!errorState)
    {
        stack.Push(current);
        RefreshDepthText();
        clearOnNext = true;
    }
}
这很简单。 我们不想尝试将错误消息压入堆栈,因此我们首先进行检查。 如果没有错误,我们将当前值压入堆栈,然后刷新“深度文本显示”(这只是显示堆栈中有多少计数)。 另外,我们将clearOnNext设置为true,因为我们将开始一个新的数字。

这是我们实际执行操作的方法:


private void DoOp(string input)
{
    if (!clearOnNext)
    {
        stack.Push(current);
    }
    if (stack.Count < 2)
    {
        errorState = true;
        clearOnNext = true;
        displayTextBox.Text = "OUT OF STACK";
        return;
    }
    double b = stack.Pop();
    double a = stack.Pop();
    stack.Push(op[input](a, B));
    double res = stack.Peek();
    if (res == double.NegativeInfinity || res == double.PositiveInfinity || res == double.NaN)
    {
        stack.Clear();
        RefreshDepthText();
        errorState = true;
        clearOnNext = true;
        displayTextBox.Text = "DIV BY ZERO";
        return;
    }
    displayTextBox.Text = stack.Peek().ToString();
    RefreshDepthText();
    clearOnNext = true;
}
第一个if语句检查是否输入了新数字。 请记住,RPN Calc的工作方式是,如果您输入数字,则操作员键会为您推送该数字。 接下来,我们检查是否可以弹出足够的值以继续。 如果您尝试执行没有足够数字的操作,则将“用尽堆栈”。 一旦知道可以,我们首先弹出两个值b(这仅对减法和除法很重要)。 现在我们执行实际操作。 我首先想到的是,我们可以使用Try / Catch来检查Div By Zero,但显然会导致double.PositiveInfinity。 顺便说一下,字符串“ Infinity”也是有效的可解析双精度型。 所以我现在只是检查结果。

无论如何,如果一切都成功,则将值偷看到文本框中,然后继续。

现在,一个敏锐的观察者会注意到,尽管我们现在已经设置为处理计算器逻辑,但实际上无法输入数字或运算符。 不用担心,这是下一部分。

输入逻辑

我们已经在只读文本框中为KeyUp设置了事件处理程序,并为每个按钮处理了Click事件。 这是这些事件处理程序的代码:


private void Button_Click(object sender, RoutedEventArgs e)
{
    string value = (sender as Button).Tag as string;
    if (numKeys.ContainsValue(value))
        ProcessInput(value);
    else
        ProcessSpecial(value);
    displayTextBox.Focus();
} 
private void DisplayTextBox_KeyUp(object sender, KeyEventArgs e)
{
    if (opKeys.ContainsKey(e.Key))
        ProcessSpecial(opKeys[e.Key]);
    else if (numKeys.ContainsKey(e.Key))
        ProcessInput(numKeys[e.Key].ToString());
    else return;
}
杂项方法

这些没有什么重要性,只是一些小事情所必需的:


private void RefreshDepthText()
{
    stackDepthTextBlock.Text = stack.Count.ToString();
} 
private void copyButton_Click(object sender, RoutedEventArgs e)
{
    Clipboard.SetText(current.ToString());
} 
private void pasteButton_Click(object sender, RoutedEventArgs e)
{
    if (!Clipboard.ContainsText())
        return;
    string s = Clipboard.GetText();
    double x;
    if (double.TryParse(s, out  x))
        displayTextBox.Text = s;
}
就是这样。 如果您正确地按照说明进行操作,那么您将拥有一个像这样的计算器: 从我的博客中发布的Cross

From: https://bytes.com/topic/xaml/insights/903343-silverlight-c-reverse-polish-notation-calculator-tutorial

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值